Logo Search packages:      
Sourcecode: wine-unstable version File versions  Download package

dsm_ctrl.c

/*
 * 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
 * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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);

struct all_devices {
      char        *modname;
      TW_IDENTITY identity;
};

static int nrdevices = 0;
static struct all_devices *devices = NULL;

static void
twain_add_onedriver(const char *dsname) {
      HMODULE     hmod;
      DSENTRYPROC dsEntry;
      TW_IDENTITY fakeOrigin;
      TW_IDENTITY sourceId;
      TW_UINT16   ret;

      hmod = LoadLibraryA(dsname);
      if (!hmod) {
            ERR("Failed to load TWAIN Source %s\n", dsname);
            return;
      }
      dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry"); 
      if (!dsEntry) {
            ERR("Failed to find DS_Entry() in TWAIN DS %s\n", dsname);
            return;
      }
      /* Loop to do multiple detects, mostly for sane.ds and gphoto2.ds */
      do {
            int i;

            sourceId.Id             = DSM_sourceId;
            sourceId.ProtocolMajor  = TWON_PROTOCOLMAJOR;
            sourceId.ProtocolMinor  = TWON_PROTOCOLMINOR;
            ret = dsEntry (&fakeOrigin, DG_CONTROL, DAT_IDENTITY, MSG_GET, &sourceId);
            if (ret != TWRC_SUCCESS) {
                  ERR("Source->(DG_CONTROL,DAT_IDENTITY,MSG_GET) failed!\n");
                  return;
            }
            TRACE("Manufacturer: %s\n",   debugstr_a(sourceId.Manufacturer));
            TRACE("ProductFamily: %s\n",  debugstr_a(sourceId.ProductFamily));
            TRACE("ProductName: %s\n",    debugstr_a(sourceId.ProductName));

            for (i=0;i<nrdevices;i++) {
                  if (!strcmp(sourceId.ProductName,devices[i].identity.ProductName))
                        break;
            }
            if (i < nrdevices)
                  break;
            if (nrdevices)
                  devices = HeapReAlloc(GetProcessHeap(), 0, devices, sizeof(devices[0])*(nrdevices+1));
            else
                  devices = HeapAlloc(GetProcessHeap(), 0, sizeof(devices[0]));
            if ((devices[nrdevices].modname = HeapAlloc(GetProcessHeap(), 0, strlen(dsname) + 1)))
                  lstrcpyA(devices[nrdevices].modname, dsname);
            devices[nrdevices].identity = sourceId;
            nrdevices++;
            DSM_sourceId++;
      } while (1);
      FreeLibrary (hmod);
}

static int detectionrun = 0;

static void
twain_autodetect(void) {
      if (detectionrun) return;
      detectionrun = 1;

      twain_add_onedriver("sane.ds");
      twain_add_onedriver("gphoto2.ds");
#if 0
      twain_add_onedriver("c:\\windows\\Twain_32\\Largan\\sp503a.ds");
      twain_add_onedriver("c:\\windows\\Twain_32\\vivicam10\\vivicam10.ds");
      twain_add_onedriver("c:\\windows\\Twain_32\\ws30slim\\sp500a.ds");
#endif
}

/* 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) {
            DSM_twCC = TWCC_NODS;
            return TWRC_FAILURE;
      }
      twRC = currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
      /* This causes crashes due to still open Windows, so leave out for now.
       * FreeLibrary (currentDS->hmod);
       */
      if (prevDS)
            prevDS->next = currentDS->next;
      else
            activeSources = currentDS->next;
      HeapFree (GetProcessHeap(), 0, currentDS);
      if (twRC == TWRC_SUCCESS)
            DSM_twCC = TWCC_SUCCESS;
      else /* FIXME: unclear how to get TWCC */
            DSM_twCC = TWCC_SEQERROR;
      return twRC;
}

/* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
      pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;

      TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
      DSM_twCC = TWCC_NODS;
      twain_autodetect();
      if (!nrdevices)
            return TWRC_FAILURE;
      *pSourceIdentity = devices[0].identity;
      DSM_twCC = TWCC_SUCCESS;
      return TWRC_SUCCESS;
}

/* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
      pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;

      TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
      twain_autodetect();
      if (!nrdevices) {
            TRACE ("no entries found.\n");
            DSM_twCC = TWCC_NODS;
            return TWRC_FAILURE;
      }
      DSM_currentDevice = 0;
      *pSourceIdentity = devices[DSM_currentDevice++].identity;
      return TWRC_SUCCESS;
}

/* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
      pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;

      TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
      if (!nrdevices || (DSM_currentDevice == nrdevices)) {
            DSM_twCC = TWCC_SUCCESS;
            return TWRC_ENDOFLIST;
      }
      *pSourceIdentity = devices[DSM_currentDevice++].identity;
      return TWRC_SUCCESS;
}

/* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
      TW_UINT16 i = 0;
      pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
      activeDS *newSource;
      const char *modname = NULL;
      HMODULE hmod;

      TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
        TRACE("pIdentity is %s\n", pIdentity->ProductName);
      if (DSM_currentState != 3) {
            FIXME("seq error\n");
            DSM_twCC = TWCC_SEQERROR;
            return TWRC_FAILURE;
      }
      twain_autodetect();
      if (!nrdevices) {
            FIXME("no devs.\n");
            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; i<nrdevices; i++)
                  if (!strcmp (devices[i].identity.ProductName, pIdentity->ProductName))
                        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;
      }
      hmod = LoadLibraryA(devices[i].modname);
      if (!hmod) {
            ERR("Failed to load TWAIN Source %s\n", modname);
            DSM_twCC = TWCC_OPERATIONERROR;
                HeapFree(GetProcessHeap(), 0, newSource);
            return TWRC_FAILURE;
      }
      newSource->hmod = hmod; 
      newSource->dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry"); 
      if (TWRC_SUCCESS != newSource->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, pIdentity)) {
            DSM_twCC = TWCC_OPERATIONERROR;
                HeapFree(GetProcessHeap(), 0, newSource);
            return TWRC_FAILURE;
      }
      /* Assign name and id for the opened data source */
      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);
      activeSources = newSource;
      DSM_twCC = TWCC_SUCCESS;
      return TWRC_SUCCESS;
}

/* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
TW_UINT16 TWAIN_UserSelect (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
      pTW_IDENTITY      selected = (pTW_IDENTITY)pData;

      if (!nrdevices) {
            DSM_twCC = TWCC_OPERATIONERROR;
            return TWRC_FAILURE;
      }
      *selected = devices[0].identity;
      DSM_twCC = TWCC_SUCCESS;
      return TWRC_SUCCESS;
}

/* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
    activeDS *currentDS = activeSources, *nextDS;

    TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");

    if (DSM_currentState == 3)
    {
        DSM_initialized = FALSE;
        DSM_currentState = 2;

        /* If there are data sources still open, close them now. */
        while (currentDS != NULL)
        {
            nextDS = currentDS->next;
          currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
            HeapFree (GetProcessHeap(), 0, currentDS);
            currentDS = nextDS;
        }
        activeSources = NULL;
        DSM_twCC = TWCC_SUCCESS;
        return TWRC_SUCCESS;
    } else {
        DSM_twCC = TWCC_SEQERROR;
        return TWRC_FAILURE;
    }
}

/* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
      TW_UINT16 twRC = TWRC_SUCCESS;

      TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
      if (DSM_currentState == 2) {
            if (!DSM_initialized) {
                  DSM_currentDevice = 0;
                  DSM_initialized = TRUE;
            }
            DSM_currentState = 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;

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

      pSourceStatus->ConditionCode = DSM_twCC;
      DSM_twCC = TWCC_SUCCESS;  /* clear the condition code */
      return TWRC_SUCCESS;
}

Generated by  Doxygen 1.6.0   Back to index