diff --git a/dlls/twain_32/Makefile.in b/dlls/twain_32/Makefile.in index 451c489370f..cadaf8081d8 100644 --- a/dlls/twain_32/Makefile.in +++ b/dlls/twain_32/Makefile.in @@ -1,4 +1,5 @@ MODULE = twain_32.dll +IMPORTS = user32 C_SRCS = \ dsm_ctrl.c \ diff --git a/dlls/twain_32/dsm_ctrl.c b/dlls/twain_32/dsm_ctrl.c index b20d55c31ae..9b878676656 100644 --- a/dlls/twain_32/dsm_ctrl.c +++ b/dlls/twain_32/dsm_ctrl.c @@ -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; } diff --git a/dlls/twain_32/twain32_main.c b/dlls/twain_32/twain32_main.c index f7b8f58223a..d1977b4d75f 100644 --- a/dlls/twain_32/twain32_main.c +++ b/dlls/twain_32/twain32_main.c @@ -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); diff --git a/dlls/twain_32/twain_i.h b/dlls/twain_32/twain_i.h index a8fa2fb94d9..f46999c6fa1 100644 --- a/dlls/twain_32/twain_i.h +++ b/dlls/twain_32/twain_i.h @@ -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