forked from openkylin/gimp
453 lines
9.7 KiB
C
453 lines
9.7 KiB
C
|
/*
|
||
|
* TWAIN Plug-in
|
||
|
* Copyright (C) 1999 Craig Setera
|
||
|
* Craig Setera <setera@home.com>
|
||
|
* 03/31/1999
|
||
|
*
|
||
|
* Updated for Mac OS X support
|
||
|
* Brion Vibber <brion@pobox.com>
|
||
|
* 07/22/2004
|
||
|
*
|
||
|
* This program is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program 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 General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Windows platform-specific code
|
||
|
*/
|
||
|
|
||
|
#include "config.h"
|
||
|
|
||
|
#include <libgimp/gimp.h>
|
||
|
|
||
|
#include "tw_platform.h"
|
||
|
#include "tw_func.h"
|
||
|
#include "tw_util.h"
|
||
|
#include "tw_local.h"
|
||
|
|
||
|
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||
|
|
||
|
int twainMessageLoop(pTW_SESSION);
|
||
|
int TwainProcessMessage(LPMSG lpMsg, pTW_SESSION twSession);
|
||
|
|
||
|
extern GimpPlugInInfo PLUG_IN_INFO;
|
||
|
extern pTW_SESSION initializeTwain ();
|
||
|
#ifdef _DEBUG
|
||
|
extern void setRunMode(char *argv[]);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#define APP_NAME "TWAIN"
|
||
|
#define SHOW_WINDOW 0
|
||
|
#define WM_TRANSFER_IMAGE (WM_USER + 100)
|
||
|
|
||
|
/* main bits */
|
||
|
static HWND hwnd = NULL;
|
||
|
static HINSTANCE hInst = NULL;
|
||
|
|
||
|
/* Storage for the DLL handle */
|
||
|
static HINSTANCE hDLL = NULL;
|
||
|
|
||
|
/* Storage for the entry point into the DSM */
|
||
|
static DSMENTRYPROC dsmEntryPoint = NULL;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* callDSM
|
||
|
*
|
||
|
* Call the specified function on the data source manager.
|
||
|
*/
|
||
|
TW_UINT16
|
||
|
callDSM(pTW_IDENTITY pOrigin,
|
||
|
pTW_IDENTITY pDest,
|
||
|
TW_UINT32 DG,
|
||
|
TW_UINT16 DAT,
|
||
|
TW_UINT16 MSG,
|
||
|
TW_MEMREF pData)
|
||
|
{
|
||
|
/* Call the function */
|
||
|
return (*dsmEntryPoint) (pOrigin, pDest, DG, DAT, MSG, pData);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* twainIsAvailable
|
||
|
*
|
||
|
* Return boolean indicating whether TWAIN is available
|
||
|
*/
|
||
|
int
|
||
|
twainIsAvailable(void)
|
||
|
{
|
||
|
/* Already loaded? */
|
||
|
if (dsmEntryPoint) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* Attempt to load the library */
|
||
|
hDLL = LoadLibrary(TWAIN_DLL_NAME);
|
||
|
if (hDLL == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
/* Look up the entry point for use */
|
||
|
dsmEntryPoint = (DSMENTRYPROC) GetProcAddress(hDLL, "DSM_Entry");
|
||
|
if (dsmEntryPoint == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
TW_HANDLE
|
||
|
twainAllocHandle (size_t size)
|
||
|
{
|
||
|
return GlobalAlloc(GHND, size);
|
||
|
}
|
||
|
|
||
|
TW_MEMREF
|
||
|
twainLockHandle (TW_HANDLE handle)
|
||
|
{
|
||
|
return GlobalLock (handle);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
twainUnlockHandle (TW_HANDLE handle)
|
||
|
{
|
||
|
GlobalUnlock (handle);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
twainFreeHandle (TW_HANDLE handle)
|
||
|
{
|
||
|
GlobalFree (handle);
|
||
|
}
|
||
|
|
||
|
gboolean
|
||
|
twainSetupCallback (pTW_SESSION twSession)
|
||
|
{
|
||
|
/* Callbacks go through the window messaging system */
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* unloadTwainLibrary
|
||
|
*
|
||
|
* Unload the TWAIN dynamic link library
|
||
|
*/
|
||
|
int
|
||
|
unloadTwainLibrary(pTW_SESSION twSession)
|
||
|
{
|
||
|
/* Explicitly free the SM library */
|
||
|
if (hDLL) {
|
||
|
FreeLibrary(hDLL);
|
||
|
hDLL=NULL;
|
||
|
}
|
||
|
|
||
|
/* the data source id will no longer be valid after
|
||
|
* twain is killed. If the id is left around the
|
||
|
* data source can not be found or opened
|
||
|
*/
|
||
|
DS_IDENTITY(twSession)->Id = 0;
|
||
|
|
||
|
/* We are now back at state 1 */
|
||
|
twSession->twainState = 1;
|
||
|
LogMessage("Source Manager successfully closed\n");
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* TwainProcessMessage
|
||
|
*
|
||
|
* Returns TRUE if the application should process message as usual.
|
||
|
* Returns FALSE if the application should skip processing of this message
|
||
|
*/
|
||
|
int
|
||
|
TwainProcessMessage(LPMSG lpMsg, pTW_SESSION twSession)
|
||
|
{
|
||
|
TW_EVENT twEvent;
|
||
|
|
||
|
twSession->twRC = TWRC_NOTDSEVENT;
|
||
|
|
||
|
/* Only ask Source Manager to process event if there is a Source connected. */
|
||
|
if (DSM_IS_OPEN(twSession) && DS_IS_OPEN(twSession)) {
|
||
|
/*
|
||
|
* A Source provides a modeless dialog box as its user interface.
|
||
|
* The following call relays Windows messages down to the Source's
|
||
|
* UI that were intended for its dialog box. It also retrieves TWAIN
|
||
|
* messages sent from the Source to our Application.
|
||
|
*/
|
||
|
twEvent.pEvent = (TW_MEMREF) lpMsg;
|
||
|
twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
|
||
|
DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT,
|
||
|
(TW_MEMREF) &twEvent);
|
||
|
|
||
|
/* Check the return code */
|
||
|
if (twSession->twRC == TWRC_NOTDSEVENT) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/* Process the message as necessary */
|
||
|
processTwainMessage(twEvent.TWMessage, twSession);
|
||
|
}
|
||
|
|
||
|
/* tell the caller what happened */
|
||
|
return (twSession->twRC == TWRC_DSEVENT);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* twainMessageLoop
|
||
|
*
|
||
|
* Process Win32 window messages and provide special handling
|
||
|
* of TWAIN specific messages. This loop will not exit until
|
||
|
* the application exits.
|
||
|
*/
|
||
|
int
|
||
|
twainMessageLoop(pTW_SESSION twSession)
|
||
|
{
|
||
|
MSG msg;
|
||
|
|
||
|
while (GetMessage(&msg, NULL, 0, 0)) {
|
||
|
if (DS_IS_CLOSED(twSession) || !TwainProcessMessage(&msg, twSession)) {
|
||
|
TranslateMessage((LPMSG)&msg);
|
||
|
DispatchMessage(&msg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return msg.wParam;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* LogLastWinError
|
||
|
*
|
||
|
* Log the last Windows error as returned by
|
||
|
* GetLastError.
|
||
|
*/
|
||
|
void
|
||
|
LogLastWinError(void)
|
||
|
{
|
||
|
LPVOID lpMsgBuf;
|
||
|
|
||
|
FormatMessage(
|
||
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
||
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||
|
NULL,
|
||
|
GetLastError(),
|
||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
|
||
|
(LPTSTR) &lpMsgBuf,
|
||
|
0,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
LogMessage("%s\n", lpMsgBuf);
|
||
|
|
||
|
/* Free the buffer. */
|
||
|
LocalFree( lpMsgBuf );
|
||
|
}
|
||
|
|
||
|
void twainQuitApplication ()
|
||
|
{
|
||
|
PostQuitMessage (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************
|
||
|
* Win32 entry point and setup...
|
||
|
******************************************************************/
|
||
|
|
||
|
/*
|
||
|
* WinMain
|
||
|
*
|
||
|
* The standard gimp entry point won't quite cut it for
|
||
|
* this plug-in. This plug-in requires creation of a
|
||
|
* standard Win32 window (hidden) in order to receive
|
||
|
* and process window messages on behalf of the TWAIN
|
||
|
* datasource.
|
||
|
*/
|
||
|
int APIENTRY
|
||
|
WinMain(HINSTANCE hInstance,
|
||
|
HINSTANCE hPrevInstance,
|
||
|
LPSTR lpCmdLine,
|
||
|
int nCmdShow)
|
||
|
{
|
||
|
|
||
|
/*
|
||
|
* Normally, we would do all of the Windows-ish set up of
|
||
|
* the window classes and stuff here in WinMain. But,
|
||
|
* the only time we really need the window and message
|
||
|
* queues is during the plug-in run. So, all of that will
|
||
|
* be done during run(). This avoids all of the Windows
|
||
|
* setup stuff for the query(). Stash the instance handle now
|
||
|
* so it is available from the run() procedure.
|
||
|
*/
|
||
|
hInst = hInstance;
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
/* When in debug version, we allow different run modes...
|
||
|
* make sure that it is correctly set.
|
||
|
*/
|
||
|
setRunMode(__argv);
|
||
|
#endif /* _DEBUG */
|
||
|
|
||
|
/*
|
||
|
* Now, call gimp_main... This is what the MAIN() macro
|
||
|
* would usually do.
|
||
|
*/
|
||
|
return gimp_main(&PLUG_IN_INFO, __argc, __argv);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* main
|
||
|
*
|
||
|
* allow to build as console app as well
|
||
|
*/
|
||
|
int main (int argc, char *argv[])
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
/* When in debug version, we allow different run modes...
|
||
|
* make sure that it is correctly set.
|
||
|
*/
|
||
|
setRunMode(__argv);
|
||
|
#endif /* _DEBUG */
|
||
|
|
||
|
/*
|
||
|
* Now, call gimp_main... This is what the MAIN() macro
|
||
|
* would usually do.
|
||
|
*/
|
||
|
return gimp_main(&PLUG_IN_INFO, __argc, __argv);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* InitApplication
|
||
|
*
|
||
|
* Initialize window data and register the window class
|
||
|
*/
|
||
|
BOOL
|
||
|
InitApplication(HINSTANCE hInstance)
|
||
|
{
|
||
|
WNDCLASS wc;
|
||
|
BOOL retValue;
|
||
|
|
||
|
/*
|
||
|
* Fill in window class structure with parameters to describe
|
||
|
* the main window.
|
||
|
*/
|
||
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||
|
wc.lpfnWndProc = (WNDPROC) WndProc;
|
||
|
wc.cbClsExtra = 0;
|
||
|
wc.cbWndExtra = 0;
|
||
|
wc.hInstance = hInstance;
|
||
|
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||
|
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
|
||
|
wc.lpszClassName = APP_NAME;
|
||
|
wc.lpszMenuName = NULL;
|
||
|
|
||
|
/* Register the window class and stash success/failure code. */
|
||
|
retValue = RegisterClass(&wc);
|
||
|
|
||
|
/* Log error */
|
||
|
if (!retValue)
|
||
|
LogLastWinError();
|
||
|
|
||
|
return retValue;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* InitInstance
|
||
|
*
|
||
|
* Create the main window for the application. Used to
|
||
|
* interface with the TWAIN datasource.
|
||
|
*/
|
||
|
BOOL
|
||
|
InitInstance(HINSTANCE hInstance, int nCmdShow, pTW_SESSION twSession)
|
||
|
{
|
||
|
/* Create our window */
|
||
|
hwnd = CreateWindow(APP_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
|
||
|
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
|
||
|
NULL, NULL, hInstance, NULL);
|
||
|
|
||
|
if (!hwnd) {
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
/* Register our window handle with the TWAIN
|
||
|
* support.
|
||
|
*/
|
||
|
registerWindowHandle(twSession, hwnd);
|
||
|
|
||
|
/* Schedule the image transfer by posting a message */
|
||
|
PostMessage(hwnd, WM_TRANSFER_IMAGE, 0, 0);
|
||
|
|
||
|
ShowWindow(hwnd, nCmdShow);
|
||
|
UpdateWindow(hwnd);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* twainWinMain
|
||
|
*
|
||
|
* This is the function that represents the code that
|
||
|
* would normally reside in WinMain (see above). This
|
||
|
* function will get called during run() in order to set
|
||
|
* up the windowing environment necessary for TWAIN to
|
||
|
* operate.
|
||
|
*/
|
||
|
int
|
||
|
twainMain()
|
||
|
{
|
||
|
/* Initialize the twain information */
|
||
|
pTW_SESSION twSession = initializeTwain();
|
||
|
|
||
|
/* Perform instance initialization */
|
||
|
if (!InitApplication(hInst))
|
||
|
return (FALSE);
|
||
|
|
||
|
/* Perform application initialization */
|
||
|
if (!InitInstance(hInst, SHOW_WINDOW, twSession))
|
||
|
return (FALSE);
|
||
|
|
||
|
/*
|
||
|
* Call the main message processing loop...
|
||
|
* This call will not return until the application
|
||
|
* exits.
|
||
|
*/
|
||
|
return twainMessageLoop(twSession);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* WndProc
|
||
|
*
|
||
|
* Process window message for the main window.
|
||
|
*/
|
||
|
LRESULT CALLBACK
|
||
|
WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
switch (message) {
|
||
|
|
||
|
case WM_TRANSFER_IMAGE:
|
||
|
/* Get an image */
|
||
|
scanImage ();
|
||
|
break;
|
||
|
|
||
|
case WM_DESTROY:
|
||
|
LogMessage("Exiting application\n");
|
||
|
PostQuitMessage(0);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return (DefWindowProc(hWnd, message, wParam, lParam));
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|