home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / twain / tw_func.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-11  |  25.5 KB  |  999 lines

  1. /*  
  2.  * TWAIN Plug-in
  3.  * Copyright (C) 1999 Craig Setera
  4.  * Craig Setera <setera@home.com>
  5.  * 03/31/1999
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20.  *
  21.  *
  22.  * Based on (at least) the following plug-ins:
  23.  * Screenshot
  24.  * GIF
  25.  * Randomize
  26.  *
  27.  * Any suggestions, bug-reports or patches are welcome.
  28.  * 
  29.  * This plug-in interfaces to the TWAIN support library in order
  30.  * to capture images from TWAIN devices directly into GIMP images.
  31.  * The plug-in is capable of acquiring the following type of
  32.  * images:
  33.  * - B/W (1 bit images translated to grayscale B/W)
  34.  * - Grayscale up to 16 bits per pixel
  35.  * - RGB up to 16 bits per sample (24, 30, 36, etc.)
  36.  * - Paletted images (both Gray and RGB)
  37.  *
  38.  * Prerequisites:
  39.  *  This plug-in will not compile on anything other than a Win32
  40.  *  platform.  Although the TWAIN documentation implies that there
  41.  *  is TWAIN support available on Macintosh, I neither have a 
  42.  *  Macintosh nor the interest in porting this.  If anyone else
  43.  *  has an interest, consult www.twain.org for more information on
  44.  *  interfacing to TWAIN.
  45.  *
  46.  * Known problems:
  47.  * - Multiple image transfers will hang the plug-in.  The current
  48.  *   configuration compiles with a maximum of single image transfers.
  49.  */
  50.  
  51. /* 
  52.  * Revision history
  53.  *  (02/07/99)  v0.1   First working version (internal)
  54.  *  (02/09/99)  v0.2   First release to anyone other than myself
  55.  *  (02/15/99)  v0.3   Added image dump and read support for debugging
  56.  *  (03/31/99)  v0.5   Added support for multi-byte samples and paletted 
  57.  *                     images.
  58.  */
  59.  
  60. #include <glib.h>        /* Needed when compiling with gcc */
  61.  
  62. #include <windows.h>
  63. #include "twain.h"
  64. #include "tw_func.h"
  65. #include "tw_util.h"
  66.  
  67. /* The DLL to be loaded for TWAIN support */
  68. #define TWAIN_DLL_NAME "TWAIN_32.DLL"
  69.  
  70. /*
  71.  * Twain error code to string mappings
  72.  */
  73. static int twainErrorCount = 0;
  74. static char *twainErrors[] = {
  75.   "No error",
  76.   "Failure due to unknown causes",
  77.   "Not enough memory to perform operation",
  78.   "No Data Source",
  79.   "DS is connected to max possible apps",
  80.   "DS or DSM reported error, application shouldn't",
  81.   "Unknown capability",
  82.   "Unrecognized MSG DG DAT combination",
  83.   "Data parameter out of range",
  84.   "DG DAT MSG out of expected sequence",
  85.   "Unknown destination App/Src in DSM_Entry",
  86.   "Capability not supported by source",
  87.   "Operation not supported by capability",
  88.   "Capability has dependency on other capability",
  89.   "File System operation is denied (file is protected)",
  90.   "Operation failed because file already exists.",
  91.   "File not found",
  92.   "Operation failed because directory is not empty",
  93.   "The feeder is jammed",
  94.   "The feeder detected multiple pages",
  95.   "Error writing the file (disk full?)",
  96.   "The device went offline prior to or during this operation",
  97.   NULL
  98. };
  99.  
  100. /* Storage for the DLL handle */
  101. static HINSTANCE hDLL = NULL;
  102.  
  103. /* Storage for the entry point into the DSM */
  104. static DSMENTRYPROC dsmEntryPoint = NULL;
  105.  
  106. /*
  107.  * FloatToFix32
  108.  *
  109.  * Convert a floating point value into a FIX32.
  110.  */
  111. TW_FIX32 FloatToFIX32(float floater)
  112. {
  113.   TW_FIX32 Fix32_value;
  114.   TW_INT32 value = (TW_INT32) (floater * 65536.0 + 0.5);
  115.   Fix32_value.Whole = value >> 16;
  116.   Fix32_value.Frac = value & 0x0000ffffL;
  117.   return (Fix32_value);
  118. }
  119.  
  120. /*
  121.  * Fix32ToFloat
  122.  *
  123.  * Convert a FIX32 value into a floating point value.
  124.  */
  125. float FIX32ToFloat(TW_FIX32 fix32)
  126. {
  127.   float floater;
  128.   floater = (float) fix32.Whole + (float) fix32.Frac / 65536.0;
  129.   return floater;
  130. }
  131.  
  132. /*
  133.  * callDSM
  134.  *
  135.  * Call the specified function on the data source manager.
  136.  */
  137. TW_UINT16
  138. callDSM(pTW_IDENTITY pOrigin,
  139.     pTW_IDENTITY pDest,
  140.     TW_UINT32    DG,
  141.     TW_UINT16    DAT,
  142.     TW_UINT16    MSG,
  143.     TW_MEMREF    pData)
  144. {
  145.   /* Call the function */
  146.   return (*dsmEntryPoint) (pOrigin, pDest, DG, DAT, MSG, pData);
  147. }
  148.  
  149. /*
  150.  * twainError
  151.  * 
  152.  * Return the TWAIN error message associated
  153.  * with the specified error code.
  154.  */
  155. char *
  156. twainError(int errorCode) 
  157. {
  158.   /* Check whether we've counted */
  159.   if (twainErrorCount == 0)
  160.     while (twainErrors[twainErrorCount++]) {}
  161.  
  162.   /* Check out of bounds */
  163.   if (errorCode >= twainErrorCount)
  164.     return "Unknown TWAIN Error Code";
  165.   else
  166.     return twainErrors[errorCode];
  167. }
  168.  
  169. /*
  170.  * currentTwainError
  171.  *
  172.  * Return the current TWAIN error message.
  173.  */
  174. char *
  175. currentTwainError(pTW_SESSION twSession)
  176. {
  177.   TW_STATUS twStatus;
  178.  
  179.   /* Get the current status code from the DSM */
  180.   twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
  181.                 DG_CONTROL, DAT_STATUS, MSG_GET,
  182.                 (TW_MEMREF) &twStatus);
  183.  
  184.   /* Return the mapped error code */
  185.   return twainError(twStatus.ConditionCode);
  186. }
  187.  
  188. /*
  189.  * twainIsAvailable
  190.  *
  191.  * Return boolean indicating whether TWAIN is available
  192.  */
  193. int
  194. twainIsAvailable(void)
  195. {
  196.   /* Already loaded? */
  197.   if (dsmEntryPoint) {
  198.     return TRUE;
  199.   }
  200.  
  201.   /* Attempt to load the library */
  202.   hDLL = LoadLibrary(TWAIN_DLL_NAME);
  203.   if (hDLL == NULL)
  204.     return FALSE;
  205.  
  206.   /* Look up the entry point for use */
  207.   dsmEntryPoint = (DSMENTRYPROC) GetProcAddress(hDLL, "DSM_Entry");
  208.   if (dsmEntryPoint == NULL)
  209.     return FALSE;
  210.  
  211.   return TRUE;
  212. }
  213.  
  214. /*
  215.  * getImage
  216.  * 
  217.  * This is a "high-level" function that can be called in order
  218.  * to take all of the steps necessary to kick off an image-transfer
  219.  * from a user-specified TWAIN datasource.  The data will be passed
  220.  * back to the callback function specified in the session structure.
  221.  */
  222. int
  223. getImage(pTW_SESSION twSession)
  224. {
  225.   /* Do some sanity checking first and bail
  226.    * if necessary.
  227.    */
  228.   if (!twainIsAvailable()) {
  229.     LogMessage("TWAIN is not available for image capture\n");
  230.     return FALSE;
  231.   }
  232.  
  233.   /* One step at a time */
  234.   if (!openDSM(twSession)) {
  235.     LogMessage("Unable to open data source manager\n");
  236.     return FALSE;
  237.   }
  238.  
  239.   if (!selectDS(twSession)) {
  240.     LogMessage("Data source not selected\n");
  241.     return FALSE;
  242.   }
  243.  
  244.   if (!openDS(twSession)) {
  245.     LogMessage("Unable to open datasource\n");
  246.     return FALSE;
  247.   }
  248.        
  249.   requestImageAcquire(twSession, TRUE);
  250.  
  251.   return TRUE;
  252. }
  253.  
  254. /*
  255.  * openDSM
  256.  *
  257.  * Open the data source manager
  258.  */
  259. int
  260. openDSM(pTW_SESSION twSession)
  261. {
  262.   /* Make sure that we aren't already open */
  263.   if (DSM_IS_OPEN(twSession))
  264.     return TRUE;
  265.  
  266.   /* Open the data source manager */
  267.   twSession->twRC = callDSM(APP_IDENTITY(twSession), NULL,
  268.                 DG_CONTROL, DAT_PARENT, MSG_OPENDSM,
  269.                 (TW_MEMREF) &(twSession->hwnd));
  270.  
  271.   /* Check the return code */
  272.   switch (twSession->twRC) {
  273.     case TWRC_SUCCESS:
  274.       /* We are now at state 3 */
  275.       twSession->twainState = 3;
  276.       return TRUE;
  277.       break;
  278.     
  279.     case TWRC_FAILURE:
  280.     default:
  281.       LogMessage("OpenDSM failure\n");
  282.       break;
  283.   }
  284.  
  285.   return FALSE;
  286. }
  287.  
  288. /*
  289.  * selectDS
  290.  *
  291.  * Select a datasource using the TWAIN user
  292.  * interface.
  293.  */
  294. int
  295. selectDS(pTW_SESSION twSession)
  296. {
  297.   /* The datasource manager must be open */
  298.   if (DSM_IS_CLOSED(twSession)) {
  299.     LogMessage("Can't select data source with closed source manager\n");
  300.     return FALSE;
  301.   }
  302.  
  303.   /* Ask TWAIN to present the source select dialog */
  304.   twSession->twRC = callDSM(APP_IDENTITY(twSession), NULL,
  305.                 DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT,
  306.                 (TW_MEMREF) DS_IDENTITY(twSession));
  307.   
  308.   /* Check the return to determine what the user decided
  309.    * to do.
  310.    */
  311.   switch (twSession->twRC) {
  312.   case TWRC_SUCCESS:
  313.     LogMessage("Data source %s selected\n", DS_IDENTITY(twSession)->ProductName);
  314.     return TRUE;
  315.     break;
  316.  
  317.   case TWRC_CANCEL:
  318.     LogMessage("User cancelled TWAIN source selection\n");
  319.     break;
  320.  
  321.   case TWRC_FAILURE:            
  322.   default:
  323.     LogMessage("Error \"%s\" during TWAIN source selection\n", 
  324.            currentTwainError(twSession));
  325.     break;
  326.   }
  327.  
  328.   return FALSE;
  329. }
  330.  
  331. /*
  332.  * selectDefaultDS
  333.  *
  334.  * Select the default datasource.
  335.  */
  336. int
  337. selectDefaultDS(pTW_SESSION twSession)
  338. {
  339.   /* The datasource manager must be open */
  340.   if (DSM_IS_CLOSED(twSession)) {
  341.     LogMessage("Can't select data source with closed source manager\n");
  342.     return FALSE;
  343.   }
  344.  
  345.   /* Ask TWAIN to present the source select dialog */
  346.   twSession->twRC = callDSM(APP_IDENTITY(twSession), NULL,
  347.                 DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT,
  348.                 (TW_MEMREF) DS_IDENTITY(twSession));
  349.  
  350.   /* Check the return code */
  351.   return (twSession->twRC == TWRC_SUCCESS);
  352. }
  353.  
  354. /*
  355.  * openDS
  356.  *
  357.  * Open a data source using the TWAIN user interface.
  358.  */
  359. int
  360. openDS(pTW_SESSION twSession)
  361. {
  362.   TW_IDENTITY *dsIdentity;
  363.  
  364.   /* The datasource manager must be open */
  365.   if (DSM_IS_CLOSED(twSession)) {
  366.     LogMessage("openDS: Cannot open data source... manager closed\n");
  367.     return FALSE;
  368.   }
  369.  
  370.   /* Is the data source already open? */
  371.   if (DS_IS_OPEN(twSession)) {
  372.     LogMessage("openDS: Data source already open\n");
  373.     return TRUE;
  374.   }
  375.  
  376.   /* Open the TWAIN datasource */
  377.   dsIdentity = DS_IDENTITY(twSession);
  378.   twSession->twRC = callDSM(APP_IDENTITY(twSession), NULL,
  379.                 DG_CONTROL, DAT_IDENTITY, MSG_OPENDS,
  380.                 (TW_MEMREF) dsIdentity);
  381.   
  382.   /* Check the return to determine what the user decided
  383.    * to do.
  384.      */
  385.   switch (twSession->twRC) {
  386.   case TWRC_SUCCESS:
  387.     /* We are now in TWAIN state 4 */
  388.     twSession->twainState = 4;
  389.     LogMessage("Data source %s opened\n", DS_IDENTITY(twSession)->ProductName);
  390.     LogMessage("\tVersion.MajorNum = %d\n", dsIdentity->Version.MajorNum);
  391.     LogMessage("\tVersion.MinorNum = %d\n", dsIdentity->Version.MinorNum);
  392.     LogMessage("\tVersion.Info = %s\n", dsIdentity->Version.Info);
  393.     LogMessage("\tProtocolMajor = %d\n", dsIdentity->ProtocolMajor);
  394.     LogMessage("\tProtocolMinor = %d\n", dsIdentity->ProtocolMinor);
  395.     LogMessage("\tManufacturer = %s\n", dsIdentity->Manufacturer);
  396.     LogMessage("\tProductFamily = %s\n", dsIdentity->ProductFamily);
  397.     return TRUE;
  398.     break;
  399.  
  400.   default:
  401.     LogMessage("Error \"%s\" opening data source\n", currentTwainError(twSession));
  402.     break;
  403.   }
  404.  
  405.   return FALSE;
  406. }
  407.  
  408. /*
  409.  * setBufferedXfer
  410.  */
  411. static int
  412. setBufferedXfer(pTW_SESSION twSession)
  413. {
  414.   TW_CAPABILITY bufXfer;
  415.   pTW_ONEVALUE pvalOneValue;
  416.  
  417.   /* Make sure the data source is open first */
  418.   if (DS_IS_CLOSED(twSession))
  419.     return FALSE;
  420.  
  421.   /* Create the capability information */
  422.   bufXfer.Cap = ICAP_XFERMECH;
  423.   bufXfer.ConType = TWON_ONEVALUE;
  424.   bufXfer.hContainer = GlobalAlloc(GHND, sizeof(TW_ONEVALUE));
  425.   pvalOneValue = (pTW_ONEVALUE) GlobalLock(bufXfer.hContainer);
  426.   pvalOneValue->ItemType = TWTY_UINT16;
  427.   pvalOneValue->Item = TWSX_MEMORY;
  428.   GlobalUnlock(bufXfer.hContainer);
  429.  
  430.   /* Make the call to the source manager */
  431.   twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
  432.                 DG_CONTROL, DAT_CAPABILITY, MSG_SET,
  433.                 (TW_MEMREF) &bufXfer);
  434.  
  435.   /* Free the container */
  436.   GlobalFree(bufXfer.hContainer);
  437.  
  438.   /* Let the caller know what happened */
  439.   return (twSession->twRC==TWRC_SUCCESS);
  440. }
  441.  
  442. /*
  443.  * requestImageAcquire
  444.  *
  445.  * Request that the acquire user interface
  446.  * be displayed.  This may or may not cause
  447.  * an image to actually be transferred.
  448.  */
  449. int
  450. requestImageAcquire(pTW_SESSION twSession, BOOL showUI)
  451. {
  452.   /* Make sure in the correct state */
  453.   if (DS_IS_CLOSED(twSession)) {
  454.     LogMessage("Can't acquire image with closed datasource\n");
  455.     return FALSE;
  456.   }
  457.  
  458.   /* Set the transfer mode */
  459.   if (setBufferedXfer(twSession)) {
  460.     TW_USERINTERFACE ui;
  461.  
  462.     /* Set the UI information */
  463.     ui.ShowUI = TRUE;
  464.     ui.ModalUI = TRUE;
  465.     ui.hParent = twSession->hwnd;
  466.  
  467.     /* Make the call to the source manager */
  468.     twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
  469.                   DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS,
  470.                   (TW_MEMREF) &ui);
  471.  
  472.     if (twSession->twRC == TWRC_SUCCESS) {
  473.       /* We are now at a new twain state */
  474.       twSession->twainState = 5;
  475.  
  476.       return TRUE;
  477.     } else {
  478.       LogMessage("Error during data source enable\n");
  479.       return FALSE;
  480.     }
  481.   } else {
  482.     LogMessage("Unable to set buffered transfer mode: %s\n", 
  483.            currentTwainError(twSession));
  484.     return FALSE;
  485.   }
  486. }
  487.  
  488. /*
  489.  * disableDS
  490.  *
  491.  * Disable the datasource associated with twSession.
  492.  */
  493. int
  494. disableDS(pTW_SESSION twSession)
  495. {
  496.     TW_USERINTERFACE ui;
  497.  
  498.     /* Verify the datasource is enabled */
  499.     if (DS_IS_DISABLED(twSession)) {
  500.         LogMessage("disableDS: Data source not enabled\n");
  501.         return TRUE;
  502.     }
  503.  
  504.     /* Set the UI information */
  505.     ui.ShowUI = TRUE;
  506.     ui.ModalUI = TRUE;
  507.     ui.hParent = twSession->hwnd;
  508.  
  509.     /* Make the call to the source manager */
  510.     twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
  511.                   DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS,
  512.                   (TW_MEMREF) &ui);
  513.  
  514.     if (twSession->twRC == TWRC_SUCCESS) {
  515.       /* We are now at a new twain state */
  516.       twSession->twainState = 4;
  517.  
  518.       return TRUE;
  519.     } else {
  520.       LogMessage("Error during data source disable\n");
  521.       return FALSE;
  522.     }
  523. }
  524.  
  525. /*
  526.  * closeDS
  527.  *
  528.  * Close the datasource associated with the 
  529.  * specified session.
  530.  */
  531. int
  532. closeDS(pTW_SESSION twSession)
  533. {
  534.   /* Can't close a closed data source */
  535.   if (DS_IS_CLOSED(twSession)) {
  536.     LogMessage("closeDS: Data source already closed\n");
  537.     return TRUE;
  538.   }
  539.  
  540.   /* Open the TWAIN datasource */
  541.   twSession->twRC = callDSM(APP_IDENTITY(twSession), NULL,
  542.                 DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS,
  543.                 (TW_MEMREF) DS_IDENTITY(twSession));
  544.   
  545.   /* Check the return to determine what the user decided
  546.    * to do.
  547.      */
  548.   switch (twSession->twRC) {
  549.   case TWRC_SUCCESS:
  550.     /* We are now in TWAIN state 3 */
  551.     twSession->twainState = 3;
  552.     LogMessage("Data source %s closed\n", DS_IDENTITY(twSession)->ProductName);
  553.     return TRUE;
  554.     break;
  555.  
  556.   default:
  557.     LogMessage("Error \"%s\" closing data source\n", currentTwainError(twSession));
  558.     break;
  559.   }
  560.  
  561.   return FALSE;
  562. }
  563.  
  564. /*
  565.  * closeDSM
  566.  *
  567.  * Close the data source manager
  568.  */
  569. int
  570. closeDSM(pTW_SESSION twSession)
  571. {
  572.   if (DSM_IS_CLOSED(twSession)) {
  573.     LogMessage("closeDSM: Source Manager not open\n");
  574.     return FALSE;
  575.   } else {
  576.     if (DS_IS_OPEN(twSession)) {
  577.       LogMessage("closeDSM: Can't close source manager with open source\n");
  578.       return FALSE;
  579.     } else {
  580.       twSession->twRC = callDSM(APP_IDENTITY(twSession), NULL,
  581.                 DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM,
  582.                 &(twSession->hwnd));
  583.                 
  584.       if (twSession->twRC != TWRC_SUCCESS) {
  585.                 LogMessage("CloseDSM failure -- %s\n", currentTwainError(twSession));
  586.       }
  587.       else {
  588.  
  589.                 /* We are now in state 2 */
  590.                 twSession->twainState = 2;
  591.       }
  592.     }
  593.   }
  594.  
  595.   /* Let the caller know what happened */
  596.   return (twSession->twRC==TWRC_SUCCESS);
  597. }
  598.  
  599. /*
  600.  * unloadTwainLibrary
  601.  *
  602.  * Unload the TWAIN dynamic link library
  603.  */
  604. int
  605. unloadTwainLibrary(pTW_SESSION twSession)
  606. {
  607.   /* Explicitly free the SM library */
  608.   if (hDLL) {        
  609.     FreeLibrary(hDLL);
  610.     hDLL=NULL;
  611.   }
  612.  
  613.   /* the data source id will no longer be valid after
  614.    * twain is killed.  If the id is left around the
  615.    * data source can not be found or opened
  616.      */
  617.   DS_IDENTITY(twSession)->Id = 0;  
  618.  
  619.     /* We are now back at state 1 */
  620.   twSession->twainState = 1;
  621.   LogMessage("Source Manager successfully closed\n");
  622.  
  623.   return TRUE;
  624. }
  625.  
  626. /*
  627.  * beginImageTransfer
  628.  *
  629.  * Begin an image transfer.
  630.  */
  631. static int
  632. beginImageTransfer(pTW_SESSION twSession, pTW_IMAGEINFO imageInfo)
  633. {
  634.   /* Clear our structures */
  635.   memset(imageInfo, 0, sizeof(TW_IMAGEINFO));
  636.  
  637.   /* Query the image information */
  638.   twSession->twRC = callDSM(
  639.                 APP_IDENTITY(twSession), DS_IDENTITY(twSession),
  640.                 DG_IMAGE, DAT_IMAGEINFO, MSG_GET,
  641.                 (TW_MEMREF) imageInfo);
  642.  
  643.   /* Check the return code */
  644.   if (twSession->twRC != TWRC_SUCCESS) {
  645.     LogMessage("Get Image Info failure - %s\n", currentTwainError(twSession));
  646.     
  647.     return FALSE;
  648.   }
  649.  
  650.   /* Call the begin transfer callback if registered */
  651.   if (twSession->transferFunctions->txfrBeginCb)
  652.     if (!(*twSession->transferFunctions->txfrBeginCb)(imageInfo, twSession->clientData))
  653.       return FALSE;
  654.  
  655.   /* We should continue */
  656.   return TRUE;
  657. }
  658.  
  659. /*
  660.  * transferImage
  661.  *
  662.  * The Source indicated it is ready to transfer data. It is 
  663.  * waiting for the application to inquire about the image details, 
  664.  * initiate the actual transfer, and, hence, transition the session 
  665.  * from State 6 to 7.  Return the reason for exiting the transfer.
  666.  */
  667. static void
  668. transferImage(pTW_SESSION twSession, pTW_IMAGEINFO imageInfo)
  669. {
  670.   TW_SETUPMEMXFER setupMemXfer;
  671.   TW_IMAGEMEMXFER imageMemXfer;
  672.   char *buffer;
  673.     
  674.   /* Clear our structures */
  675.   memset(&setupMemXfer, 0, sizeof(TW_SETUPMEMXFER));
  676.   memset(&imageMemXfer, 0, sizeof(TW_IMAGEMEMXFER));
  677.     
  678.   /* Find out how the source would like to transfer... */
  679.   twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
  680.                 DG_CONTROL, DAT_SETUPMEMXFER, MSG_GET,
  681.                 (TW_MEMREF) &setupMemXfer);
  682.     
  683.   /* Allocate the buffer for the transfer */
  684.   buffer = g_new (char, setupMemXfer.Preferred);
  685.   imageMemXfer.Memory.Flags = TWMF_APPOWNS | TWMF_POINTER;
  686.   imageMemXfer.Memory.Length = setupMemXfer.Preferred;
  687.   imageMemXfer.Memory.TheMem = (TW_MEMREF) buffer;
  688.     
  689.   /* Get the data */
  690.   do {
  691.     /* Setup for the memory transfer */
  692.     imageMemXfer.Compression = TWON_DONTCARE16;
  693.     imageMemXfer.BytesPerRow = TWON_DONTCARE32;
  694.     imageMemXfer.Columns = TWON_DONTCARE32;
  695.     imageMemXfer.Rows = TWON_DONTCARE32;
  696.     imageMemXfer.XOffset = TWON_DONTCARE32;
  697.     imageMemXfer.YOffset = TWON_DONTCARE32;
  698.     imageMemXfer.BytesWritten = TWON_DONTCARE32;
  699.         
  700.     /* Get the next block of memory */
  701.     twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
  702.                   DG_IMAGE, DAT_IMAGEMEMXFER, MSG_GET,
  703.                   (TW_MEMREF) &imageMemXfer);
  704.         
  705.     if ((twSession->twRC == TWRC_SUCCESS) ||
  706.     (twSession->twRC == TWRC_XFERDONE)) {
  707.       /* Call the callback function */
  708.       if (!(*twSession->transferFunctions->txfrDataCb) (
  709.                             imageInfo, 
  710.                             &imageMemXfer,    
  711.                             twSession->clientData)) {
  712.     /* Callback function requested to cancel */
  713.     twSession->twRC = TWRC_CANCEL;
  714.     break;
  715.       }
  716.     }
  717.   } while (twSession->twRC == TWRC_SUCCESS);
  718.  
  719.   /* Free the memory buffer */
  720.   g_free (imageMemXfer.Memory.TheMem);
  721. }
  722.  
  723. /*
  724.  * endPendingTransfer
  725.  *
  726.  * Cancel the currently pending transfer.
  727.  * Return the count of pending transfers.
  728.  */
  729. static int
  730. endPendingTransfer(pTW_SESSION twSession)
  731. {
  732.   TW_PENDINGXFERS pendingXfers;
  733.  
  734.   twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
  735.                 DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER,
  736.                 (TW_MEMREF) &pendingXfers);
  737.  
  738.   if (!pendingXfers.Count)
  739.     twSession->twainState = 5;
  740.  
  741.   return pendingXfers.Count;
  742. }
  743.  
  744. /*
  745.  * cancelPendingTransfers
  746.  *
  747.  * Cancel all pending image transfers.
  748.  */
  749. void
  750. cancelPendingTransfers(pTW_SESSION twSession)
  751. {
  752.   TW_PENDINGXFERS pendingXfers;
  753.  
  754.   twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
  755.                   DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET,
  756.                   (TW_MEMREF) &pendingXfers);
  757. }
  758.  
  759. /*
  760.  * endImageTransfer
  761.  *
  762.  * Finish transferring an image.  Return the count
  763.  * of pending images.
  764.  */
  765. static int
  766. endImageTransfer(pTW_SESSION twSession, int *pendingCount)
  767. {
  768.   BOOL continueTransfers;
  769.   int exitCode = twSession->twRC;
  770.  
  771.   /* Have now exited the transfer for some reason... Figure out
  772.    * why and what to do about it
  773.    */
  774.   switch (twSession->twRC) {
  775.   case TWRC_XFERDONE:
  776.   case TWRC_CANCEL:
  777.     LogMessage("Xfer done received\n");
  778.     *pendingCount = endPendingTransfer(twSession);
  779.     break;
  780.  
  781.   case TWRC_FAILURE:
  782.     LogMessage("Failure received\n");
  783.     *pendingCount = endPendingTransfer(twSession);
  784.     break;
  785.   }
  786.  
  787.   /* Call the end transfer callback */
  788.   if (twSession->transferFunctions->txfrEndCb)
  789.     continueTransfers = 
  790.       (*twSession->transferFunctions->txfrEndCb)(exitCode, 
  791.                          *pendingCount, 
  792.                          twSession->clientData);
  793.  
  794.   return (*pendingCount && continueTransfers);
  795. }
  796.  
  797. /*
  798.  * transferImages
  799.  *
  800.  * Transfer all of the images that are available from the
  801.  * datasource.
  802.  */
  803. static void
  804. transferImages(pTW_SESSION twSession)
  805. {
  806.   TW_IMAGEINFO imageInfo;
  807.   int pendingCount;
  808.  
  809.   /* Check the image transfer callback function
  810.    * before even attempting to do the transfer
  811.    */
  812.   if (!twSession->transferFunctions || !twSession->transferFunctions->txfrDataCb) {
  813.     LogMessage("Attempting image transfer without callback function\n");
  814.     return;
  815.   }
  816.  
  817.   /*
  818.    * Inform our application that we are getting ready
  819.    * to transfer images.
  820.    */
  821.   if (twSession->transferFunctions->preTxfrCb)
  822.     (*twSession->transferFunctions->preTxfrCb)(twSession->clientData);
  823.  
  824.   /* Loop through the available images */
  825.   do {
  826.     /* Move to the new state */
  827.     twSession->twainState = 6;
  828.         
  829.     /* Begin the image transfer */
  830.     if (!beginImageTransfer(twSession, &imageInfo))
  831.       continue;
  832.         
  833.     /* Call the image transfer function */
  834.     transferImage(twSession, &imageInfo);
  835.         
  836.   } while (endImageTransfer(twSession, &pendingCount));
  837.  
  838.   /*
  839.    * Inform our application that we are done
  840.    * transferring images.
  841.    */
  842.   if (twSession->transferFunctions->postTxfrCb)
  843.     (*twSession->transferFunctions->postTxfrCb)(pendingCount,
  844.                         twSession->clientData);
  845. }
  846.  
  847. /*
  848.  * TwainProcessMessage
  849.  *
  850.  * Returns TRUE if the application should process message as usual.
  851.  * Returns FALSE if the application should skip processing of this message
  852.  */
  853. int
  854. TwainProcessMessage(LPMSG lpMsg, pTW_SESSION twSession)
  855. {
  856.   TW_EVENT   twEvent;
  857.     
  858.   twSession->twRC = TWRC_NOTDSEVENT;
  859.     
  860.   /* Only ask Source Manager to process event if there is a Source connected. */
  861.   if (DSM_IS_OPEN(twSession) && DS_IS_OPEN(twSession)) {
  862.         /*
  863.          * A Source provides a modeless dialog box as its user interface.
  864.          * The following call relays Windows messages down to the Source's
  865.          * UI that were intended for its dialog box.  It also retrieves TWAIN
  866.          * messages sent from the Source to our Application.
  867.          */
  868.         twEvent.pEvent = (TW_MEMREF) lpMsg;
  869.         twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
  870.             DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT, 
  871.             (TW_MEMREF) &twEvent);
  872.         
  873.         /* Check the return code */
  874.         if (twSession->twRC == TWRC_NOTDSEVENT) {
  875.             return FALSE;
  876.         }
  877.         
  878.         /* Process the message as necessary */
  879.         switch (twEvent.TWMessage) {
  880.         case MSG_XFERREADY:
  881.             LogMessage("Source says that data is ready\n");
  882.             transferImages(twSession);
  883.             break;
  884.             
  885.         case MSG_CLOSEDSREQ:
  886.             /* Disable the datasource, Close the Data source
  887.              * and close the data source manager
  888.              */
  889.             LogMessage("CloseDSReq\n");
  890.             disableDS(twSession);
  891.             closeDS(twSession);
  892.             closeDSM(twSession);
  893.             break;
  894.             
  895.             /* No message from the Source to the App break;
  896.              * possible new message
  897.              */
  898.         case MSG_NULL:
  899.         default:
  900.             break;
  901.         }   
  902.   } 
  903.     
  904.   /* tell the caller what happened */
  905.   return (twSession->twRC == TWRC_DSEVENT);
  906.  
  907. /*
  908.  * twainMessageLoop
  909.  *
  910.  * Process Win32 window messages and provide special handling
  911.  * of TWAIN specific messages.  This loop will not exit until
  912.  * the application exits.
  913.  */
  914. int
  915. twainMessageLoop(pTW_SESSION twSession) 
  916. {
  917.   MSG msg;
  918.     
  919.   while (GetMessage(&msg, NULL, 0, 0)) {
  920.     if (DS_IS_CLOSED(twSession) || !TwainProcessMessage(&msg, twSession)) {
  921.       TranslateMessage((LPMSG)&msg);
  922.       DispatchMessage(&msg);
  923.     }
  924.   }
  925.     
  926.   return msg.wParam;
  927. }
  928.  
  929. /**********************************************************************
  930.  * Session related functions
  931.  **********************************************************************/
  932.  
  933. /*
  934.  * newSession
  935.  *
  936.  * Create a new TWAIN session.
  937.  */
  938. pTW_SESSION
  939. newSession(pTW_IDENTITY appIdentity) {
  940.   /* Create the structure */
  941.   pTW_SESSION session = g_new (TW_SESSION, 1);
  942.  
  943.   /* Set the structure fields */
  944.   session->hwnd = 0;
  945.   session->twRC = TWRC_SUCCESS;
  946.   session->appIdentity = appIdentity;
  947.   session->dsIdentity = g_new (TW_IDENTITY, 1);
  948.   session->dsIdentity->Id = 0;
  949.   session->dsIdentity->ProductName[0] = '\0';
  950.   session->transferFunctions = NULL;
  951.  
  952.   if (twainIsAvailable())
  953.     session->twainState = 2;
  954.   else
  955.     session->twainState = 0;
  956.  
  957.   return session;
  958. }
  959.  
  960. /*
  961.  * registerWindowHandle
  962.  *
  963.  * Register the window handle to be used for this
  964.  * session.
  965.  */
  966. void
  967. registerWindowHandle(pTW_SESSION session, HWND hwnd)
  968. {
  969.   session->hwnd = hwnd;
  970. }
  971.  
  972. /*
  973.  * registerTransferCallback
  974.  *
  975.  * Register the callback to use when transferring
  976.  * image data.
  977.  */
  978. void 
  979. registerTransferCallbacks(pTW_SESSION session, 
  980.               pTXFR_CB_FUNCS txfrFuncs, 
  981.               void *clientData)
  982. {
  983.   session->transferFunctions = txfrFuncs;
  984.   session->clientData = clientData;
  985. }
  986.  
  987. /*
  988.  * setClientData
  989.  *
  990.  * Set the client data associated with the specified
  991.  * TWAIN session.
  992.  */
  993. void
  994. setClientData(pTW_SESSION session, void *clientData)
  995. {
  996.   session->clientData = clientData;
  997. }
  998.