twain_32: Add support for DAT_NULL commands.

Signed-off-by: Vincent Povirk <vincent@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Vincent Povirk 2017-10-20 14:16:26 -05:00 committed by Alexandre Julliard
parent 8a118c2e0f
commit 24a10e301a
4 changed files with 132 additions and 0 deletions

View File

@ -1,4 +1,5 @@
MODULE = twain_32.dll
IMPORTS = user32
C_SRCS = \
dsm_ctrl.c \

View File

@ -27,6 +27,7 @@
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "twain.h"
#include "twain_i.h"
#include "wine/debug.h"
@ -36,6 +37,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(twain);
static TW_UINT16 DSM_initialized; /* whether Source Manager is initialized */
static TW_UINT32 DSM_sourceId; /* source id generator */
static TW_UINT16 DSM_currentDevice; /* keep track of device during enumeration */
static HWND DSM_parent;
static UINT event_message;
struct all_devices {
char *modname;
@ -114,6 +117,86 @@ twain_autodetect(void) {
#endif
}
/* DG_CONTROL/DAT_NULL/MSG_CLOSEDSREQ|MSG_DEVICEEVENT|MSG_XFERREADY */
TW_UINT16 TWAIN_ControlNull (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, activeDS *pSource, TW_UINT16 MSG, TW_MEMREF pData)
{
struct pending_message *message;
TRACE ("DG_CONTROL/DAT_NULL MSG=%i\n", MSG);
if (MSG != MSG_CLOSEDSREQ &&
MSG != MSG_DEVICEEVENT &&
MSG != MSG_XFERREADY)
{
DSM_twCC = TWCC_BADPROTOCOL;
return TWRC_FAILURE;
}
message = HeapAlloc(GetProcessHeap(), 0, sizeof(*message));
if (!message)
{
DSM_twCC = TWCC_LOWMEMORY;
return TWRC_FAILURE;
}
message->msg = MSG;
list_add_tail(&pSource->pending_messages, &message->entry);
/* Delphi twain only sends us messages from one window, and it
doesn't even give us the real handle to that window. Other
applications might decide to forward messages sent to DSM_parent
or to the one supplied to ENABLEDS. So let's try very hard to
find a window that will work. */
if (DSM_parent)
PostMessageW(DSM_parent, event_message, 0, 0);
if (pSource->ui_window && pSource->ui_window != DSM_parent)
PostMessageW(pSource->ui_window, event_message, 0, 0);
if (pSource->event_window && pSource->event_window != pSource->ui_window &&
pSource->event_window != DSM_parent)
PostMessageW(pSource->event_window, event_message, 0, 0);
PostMessageW(0, event_message, 0, 0);
return TWRC_SUCCESS;
}
/* Filters MSG_PROCESSEVENT messages before reaching the data source */
TW_UINT16 TWAIN_ProcessEvent (pTW_IDENTITY pOrigin, activeDS *pSource, TW_MEMREF pData)
{
TW_EVENT *event = (TW_EVENT*)pData;
MSG *msg = (MSG*)event->pEvent;
TW_UINT16 result = TWRC_NOTDSEVENT;
TRACE("%x,%x\n", msg->message, event_message);
if (msg->message == event_message)
{
if (!list_empty (&pSource->pending_messages))
{
struct list *entry = list_head (&pSource->pending_messages);
struct pending_message *message = LIST_ENTRY(entry, struct pending_message, entry);
event->TWMessage = message->msg;
list_remove (entry);
TRACE("<-- %x\n", event->TWMessage);
}
else
event->TWMessage = MSG_NULL;
result = TWRC_DSEVENT;
}
if (msg->hwnd)
{
MSG dummy;
pSource->event_window = msg->hwnd;
if (!list_empty (&pSource->pending_messages) &&
!PeekMessageW(&dummy, msg->hwnd, event_message, event_message, PM_NOREMOVE))
{
PostMessageW(msg->hwnd, event_message, 0, 0);
}
}
return result;
}
/* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
@ -254,6 +337,9 @@ TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
newSource->next = activeSources;
newSource->identity.Id = pIdentity->Id;
strcpy (newSource->identity.ProductName, pIdentity->ProductName);
list_init(&newSource->pending_messages);
newSource->ui_window = NULL;
newSource->event_window = NULL;
activeSources = newSource;
DSM_twCC = TWCC_SUCCESS;
return TWRC_SUCCESS;
@ -299,6 +385,7 @@ TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
currentDS = nextDS;
}
activeSources = NULL;
DSM_parent = NULL;
DSM_twCC = TWCC_SUCCESS;
return TWRC_SUCCESS;
} else {
@ -314,6 +401,7 @@ TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
if (!DSM_initialized) {
event_message = RegisterWindowMessageA("WINE TWAIN_32 EVENT");
DSM_currentDevice = 0;
DSM_initialized = TRUE;
DSM_twCC = TWCC_SUCCESS;
@ -323,6 +411,7 @@ TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
DSM_twCC = TWCC_SEQERROR;
twRC = TWRC_FAILURE;
}
DSM_parent = (HWND)pData;
return twRC;
}

View File

@ -142,6 +142,19 @@ DSM_Entry (pTW_IDENTITY pOrigin,
TRACE("(DG=%d DAT=%d MSG=%d)\n", DG, DAT, MSG);
if (DG == DG_CONTROL && DAT == DAT_NULL)
{
activeDS *pSource = TWAIN_LookupSource (pOrigin);
if (!pSource)
{
ERR("No source associated with pSource %p\n", pDest);
DSM_twCC = TWCC_BADPROTOCOL;
return TWRC_FAILURE;
}
return TWAIN_ControlNull (pOrigin, pDest, pSource, MSG, pData);
}
if (pDest)
{
activeDS *pSource = TWAIN_LookupSource (pDest);
@ -152,6 +165,21 @@ DSM_Entry (pTW_IDENTITY pOrigin,
DSM_twCC = TWCC_BADDEST;
return TWRC_FAILURE;
}
if (DG == DG_CONTROL && DAT == DAT_EVENT && MSG == MSG_PROCESSEVENT)
{
twRC = TWAIN_ProcessEvent(pOrigin, pSource, pData);
if (twRC == TWRC_DSEVENT)
return twRC;
}
if (DG == DG_CONTROL && DAT == DAT_USERINTERFACE &&
(MSG == MSG_ENABLEDS || MSG == MSG_ENABLEDSUIONLY) &&
pData != NULL)
{
pSource->ui_window = ((TW_USERINTERFACE*)pData)->hParent;
}
DSM_twCC = TWCC_SUCCESS;
TRACE("Forwarding %d/%d/%d/%p to DS.\n", DG, DAT, MSG, pData);
twRC = pSource->dsEntry(pOrigin, DG, DAT, MSG, pData);

View File

@ -29,6 +29,13 @@
#include "windef.h"
#include "winbase.h"
#include "twain.h"
#include "wine/list.h"
struct pending_message
{
struct list entry;
TW_UINT16 msg;
};
/* internal information about an active data source */
typedef struct tagActiveDS
@ -37,6 +44,9 @@ typedef struct tagActiveDS
TW_IDENTITY identity; /* identity */
HMODULE hmod;
DSENTRYPROC dsEntry;
struct list pending_messages;
HWND ui_window;
HWND event_window;
} activeDS;
TW_UINT16 DSM_twCC DECLSPEC_HIDDEN; /* current condition code of Source Manager */
@ -62,5 +72,9 @@ extern TW_UINT16 TWAIN_OpenDSM
(pTW_IDENTITY pOrigin, TW_MEMREF pData) DECLSPEC_HIDDEN;
extern TW_UINT16 TWAIN_GetDSMStatus
(pTW_IDENTITY pOrigin, TW_MEMREF pData) DECLSPEC_HIDDEN;
extern TW_UINT16 TWAIN_ControlNull
(pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, activeDS *pSource, TW_UINT16 MSG, TW_MEMREF pData) DECLSPEC_HIDDEN;
extern TW_UINT16 TWAIN_ProcessEvent
(pTW_IDENTITY pOrigin, activeDS *pSource, TW_MEMREF pData) DECLSPEC_HIDDEN;
#endif