The start of the script FuncDefs a couple Windows OS functions we need in order to display a DIB in our GUI window. We call GuiWindowDefaults to enable twain support, then call TwainInit, and finally TwainOpenDSM to open the Data Source manager. The order of these calls is fairly important.
When the user selects the Acquire menu item, we call TwainAcquire.
When the twain device finally signals us that the image is ready to be retrieved, we call TwainGetImage to retrieve it. We tell TwainGetImage to call our subroutine named HandleBitmap. This subroutine calls TwainCreateDIB to get a DIB of the bitmap handle passed by TwainGetImage. Then our subroutine returns a 1 to tell TwainGetImage to free that bitmap handle (now that we have our own DIB of it). We could call TwainSaveDIB here if we wanted to save the image to disk.
Where we draw the bitmap is in our WM_PAINT event handler.
/* GUIBEGIN WINDOW , 0, 0, 400, 200, POPUP|CAPTION|SYSMENU|MINBOX|MAXBOX|THICK, , Twain Demo FONT 8, 400, MS Shell Dlg MENU DEND MENU HEADING &Twain ITEM Ac&quire..., AcquireTwain ITEM &Select Source..., PickTwainSource < DEND GUIEND */ LIBRARY rexxgui NUMERIC DIGITS 10 DO FuncDef("BeginPaint","32u,void,void stor","user32") FuncDef("EndPaint","32,void,void","user32") CATCH FAILURE CONDITION("M") RETURN END /* We want SYNTAX raised for REXX GUI and TWAIN functions. */ GuiErr = "SYNTAX" GuiHeading = 1 TwainErr = "SYNTAX" TwainHeading = 1 /* No DIB yet gotten */ DIB = 0 DO /* Call GuiWindowDefaults() and indicate we want TWAIN support enabled. You * likely would pass other values too if you want extended support, such as * your own icon, cursor, HTML support, etc. NOTE: GuiWindowDefaults() must * be called BEFORE any windows are open, or any TWAIN functions are called. */ GuiWindowDefaults(, , , , "TWAIN") /* Initialize TWAIN support. */ TwainInit(1 /* USA */, "Twain Demo", 1) GuiCreateWindow('NORMAL') /* Open the Twain Data Source manager. Tell it to report * TWAIN events to our above window. */ TwainOpenDSM(GuiWindow) /* We trap SYNTAX just in case any initialization above fails. */ CATCH SYNTAX CONDITION('M') /* Close the TWAIN Data Source manager if it was open. NOTE: * This is safe to call even if not open. */ TwainCloseDSM() /* End the script. */ RETURN END Again: DO FOREVER GuiGetMsg() IF EXISTS('GuiObject') == 0 THEN DO IF EXISTS('GuiSignal') THEN DO END END ELSE DO IF EXISTS('GuiSignal') == 0 THEN DROP (GuiObject) ELSE SELECT GuiObject /* Was it some Twain event? If so, then GuiObject == 'TWAIN'. NOTE: This * implies that you should never create a child window layout with an * object name of 'TWAIN' if you're using twain support. */ WHEN 'TWAIN' THEN DO /* Is another image (bitmap) ready for us to retrieve from the TWAIN * data source? */ IF GuiSignal == 'XFER' THEN DO /* Fill in our "BitmapInfo" stem variable with information about * the image. This isn't a required step. It's just something * that you can do if you want a little more information about * the image before you do the TwainGetImage() below. */ TwainGetImageInfo("BitmapInfo") /* Fetch the image, and call our subroutine "HandleBitmap" to do * something with it. Alternately, we could call TwainAck() to * skip this image, or TwainCancel() to cancel the transfer of * all remaining images. */ TwainGetImage("HandleBitmap") /* Force the window to be redrawn */ GuiRefresh(, 1) END END /* TWAIN */ OTHERWISE END END CATCH SYNTAX IF GuiInfo() \== "" THEN DO CONDITION('M') SIGNAL Again END FINALLY GuiDestroyWindow() END RETURN /* ==================== TwainAcquire() ================== * The event handler for the "Twain -> Acquire..." menu * item. Reginald calls this when the user selects that * item. */ AcquireTwain: /* Free any DIB we got before. It's OK to call this even if * we didn't get a DIB */ TwainFreeDIB(DIB) /* Start an Acquire operation. GuiGetMsg() will return as * each image is ready for us to TwainGetImage(). NOTE: * TwainAcquire() will open whatever data source the user * selected via TwainSelectSource() and then close it when * we're done with the Acquire operation. We accept only * 1 image. */ TwainAcquire(1) RETURN /* ==================== TwainSource() ================== * The event handler for the "Twain -> Select source..." * menu item. Reginald calls this when the user selects * that item. */ PickTwainSource: /* Present a dialog box listing the names of all the * available TWAIN data sources on this computer, and * let the user pick one. NOTE: If an error or cancel, * SYNTAX is raised. */ TwainSelectSource() RETURN /* ==================== HandleBitmap() ================== * Called by TwainGetImage() to pass us the handle to some * bitmap of the next acquired image. Here we do whatever * we want with the bitmap (ie, save it to disk, display * it in a window, etc). Then we return one of the following: * * 1 = Free the bitmap. * 0 = Don't free the bitmap (ie, we will take responsibility * for it). * No return = Free the bitmap and cancel the acquire operation. */ HandleBitmap: /* Get a Device Independent Bitmap (DIB) from the passed handle */ DIB = TwainCreateDIB(ARG(1)) /* If we wanted to save the image to disk, we could do so. But * we need a filename for it. It wouldn't be good to present a * file dialog here, right in the middle of an acquire operation, * so one alternative would be to create a temporary filename. */ /* TwainSaveDIB(DIB, "C:\MyImage.bmp") */ /* Let RXTWAIN free the handle now */ RETURN 1 /* ==================== WM_PAINT() ===================== * The PAINT event handler for my window. Reginald calls * this whenever the window needs to be redrawn. */ WM_PAINT: /* Erase the background and get a device context */ hDC = BeginPaint(GuiWindow, ps) /* Draw the bitmap */ TwainDrawDIB(DIB, hDC) /* End paint */ EndPaint(GuiWindow, ps) /* Don't let REXX GUI handle this */ RETURN ""