https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0edcbac349451ffbf0a99…
commit 0edcbac349451ffbf0a99e84a4a8ad74ea641096
Author: Amine Khaldi <amine.khaldi(a)reactos.org>
AuthorDate: Sat Jan 20 13:17:45 2018 +0100
Commit: Amine Khaldi <amine.khaldi(a)reactos.org>
CommitDate: Sat Jan 20 13:17:45 2018 +0100
[TWAIN_32] Sync with Wine 3.0. CORE-14225
---
dll/win32/twain_32/CMakeLists.txt | 2 +-
dll/win32/twain_32/dsm_ctrl.c | 206 ++++++++++++++++++++++++++++++++++++--
dll/win32/twain_32/resource.h | 24 +++++
dll/win32/twain_32/twain.rc | 33 ++++++
dll/win32/twain_32/twain32_main.c | 46 +++++++++
dll/win32/twain_32/twain_32.rc | 3 +
dll/win32/twain_32/twain_i.h | 17 ++++
media/doc/README.WINE | 2 +-
8 files changed, 321 insertions(+), 12 deletions(-)
diff --git a/dll/win32/twain_32/CMakeLists.txt b/dll/win32/twain_32/CMakeLists.txt
index d25fde9596..ac028ed450 100644
--- a/dll/win32/twain_32/CMakeLists.txt
+++ b/dll/win32/twain_32/CMakeLists.txt
@@ -15,6 +15,6 @@ add_library(twain_32 SHARED
set_module_type(twain_32 win32dll)
target_link_libraries(twain_32 wine)
-add_importlibs(twain_32 msvcrt kernel32 ntdll)
+add_importlibs(twain_32 user32 msvcrt kernel32 ntdll)
add_pch(twain_32 twain_i.h SOURCE)
add_cd_file(TARGET twain_32 DESTINATION reactos FOR all)
diff --git a/dll/win32/twain_32/dsm_ctrl.c b/dll/win32/twain_32/dsm_ctrl.c
index aa2a4c1188..ce845c9531 100644
--- a/dll/win32/twain_32/dsm_ctrl.c
+++ b/dll/win32/twain_32/dsm_ctrl.c
@@ -21,9 +21,15 @@
#include "twain_i.h"
+#include <winuser.h>
+
+#include "resource.h"
+
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;
@@ -102,6 +108,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)
{
@@ -230,34 +316,131 @@ TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
}
newSource->hmod = hmod;
newSource->dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry");
+ /* Assign id for the opened data source */
+ pIdentity->Id = DSM_sourceId ++;
if (TWRC_SUCCESS != newSource->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY,
MSG_OPENDS, pIdentity)) {
DSM_twCC = TWCC_OPERATIONERROR;
HeapFree(GetProcessHeap(), 0, newSource);
+ DSM_sourceId--;
return TWRC_FAILURE;
}
- /* Assign name and id for the opened data source */
- pIdentity->Id = DSM_sourceId ++;
/* add the data source to an internal active source list */
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;
}
+typedef struct {
+ pTW_IDENTITY origin;
+ pTW_IDENTITY result;
+} userselect_data;
+
+static INT_PTR CALLBACK userselect_dlgproc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM
lparam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ userselect_data *data = (userselect_data*)lparam;
+ int i;
+ HWND sourcelist;
+ BOOL any_devices = FALSE;
+
+ SetWindowLongPtrW(hwnd, DWLP_USER, (LONG_PTR)data);
+
+ sourcelist = GetDlgItem(hwnd, IDC_LISTSOURCE);
+
+ for (i=0; i<nrdevices; i++)
+ {
+ TW_IDENTITY *id = &devices[i].identity;
+ LRESULT index;
+
+ if ((id->SupportedGroups & data->origin->SupportedGroups) == 0)
+ continue;
+
+ index = SendMessageA(sourcelist, LB_ADDSTRING, 0,
(LPARAM)id->ProductName);
+ SendMessageW(sourcelist, LB_SETITEMDATA, (WPARAM)index, (LPARAM)i);
+ any_devices = TRUE;
+ }
+
+ if (any_devices)
+ {
+ EnableWindow(GetDlgItem(hwnd, IDOK), TRUE);
+
+ /* FIXME: Select the supplied product name or default source. */
+ SendMessageW(sourcelist, LB_SETCURSEL, 0, 0);
+ }
+
+ return TRUE;
+ }
+ case WM_CLOSE:
+ EndDialog(hwnd, 0);
+ return TRUE;
+ case WM_COMMAND:
+ if (wparam == MAKEWPARAM(IDCANCEL, BN_CLICKED))
+ {
+ EndDialog(hwnd, 0);
+ return TRUE;
+ }
+ else if (wparam == MAKEWPARAM(IDOK, BN_CLICKED) ||
+ wparam == MAKEWPARAM(IDC_LISTSOURCE, LBN_DBLCLK))
+ {
+ userselect_data *data = (userselect_data*)GetWindowLongPtrW(hwnd,
DWLP_USER);
+ HWND sourcelist;
+ LRESULT index;
+
+ sourcelist = GetDlgItem(hwnd, IDC_LISTSOURCE);
+
+ index = SendMessageW(sourcelist, LB_GETCURSEL, 0, 0);
+
+ if (index == LB_ERR)
+ return TRUE;
+
+ index = SendMessageW(sourcelist, LB_GETITEMDATA, (WPARAM)index, 0);
+
+ *data->result = devices[index].identity;
+
+ /* FIXME: Save this as the default source */
+
+ EndDialog(hwnd, 1);
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
/* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
TW_UINT16 TWAIN_UserSelect (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
- pTW_IDENTITY selected = (pTW_IDENTITY)pData;
+ userselect_data param = {pOrigin, pData};
+ HWND parent = DSM_parent;
- if (!nrdevices) {
- DSM_twCC = TWCC_OPERATIONERROR;
- return TWRC_FAILURE;
- }
- *selected = devices[0].identity;
- DSM_twCC = TWCC_SUCCESS;
- return TWRC_SUCCESS;
+ TRACE("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT SupportedGroups=0x%x
ProductName=%s\n",
+ pOrigin->SupportedGroups, wine_dbgstr_a(param.result->ProductName));
+
+ twain_autodetect();
+
+ if (!IsWindow(parent))
+ parent = NULL;
+
+ if (DialogBoxParamW(DSM_hinstance, MAKEINTRESOURCEW(DLG_USERSELECT),
+ parent, userselect_dlgproc, (LPARAM)¶m) == 0)
+ {
+ TRACE("canceled\n");
+ DSM_twCC = TWCC_SUCCESS;
+ return TWRC_CANCEL;
+ }
+
+ TRACE("<-- %s\n", wine_dbgstr_a(param.result->ProductName));
+ DSM_twCC = TWCC_SUCCESS;
+ return TWRC_SUCCESS;
}
/* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
@@ -280,6 +463,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 {
@@ -295,6 +479,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;
@@ -304,6 +489,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/dll/win32/twain_32/resource.h b/dll/win32/twain_32/resource.h
new file mode 100644
index 0000000000..1cbc26e733
--- /dev/null
+++ b/dll/win32/twain_32/resource.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <windef.h>
+#include <winuser.h>
+
+#define DLG_USERSELECT 1
+
+#define IDC_LISTSOURCE 1001
diff --git a/dll/win32/twain_32/twain.rc b/dll/win32/twain_32/twain.rc
new file mode 100644
index 0000000000..339ead68bb
--- /dev/null
+++ b/dll/win32/twain_32/twain.rc
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "resource.h"
+
+#pragma makedep po
+
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+DLG_USERSELECT DIALOG 0, 0, 140, 140
+STYLE DS_MODALFRAME | DS_3DLOOK | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_POPUP |
DS_NOIDLEMSG
+FONT 8, "MS Shell Dlg"
+CAPTION "Select Source"
+{
+ LISTBOX IDC_LISTSOURCE, 7, 7, 126, 104
+ DEFPUSHBUTTON "OK", IDOK, 29, 118, 50, 15,
BS_DEFPUSHBUTTON|WS_TABSTOP|WS_DISABLED
+ PUSHBUTTON "Cancel", IDCANCEL, 83, 118, 50, 15
+}
diff --git a/dll/win32/twain_32/twain32_main.c b/dll/win32/twain_32/twain32_main.c
index 4044cb2dcc..1607c9b2d7 100644
--- a/dll/win32/twain_32/twain32_main.c
+++ b/dll/win32/twain_32/twain32_main.c
@@ -21,6 +21,24 @@
#include "twain_i.h"
+extern HINSTANCE DSM_hinstance;
+
+BOOL WINAPI DllMain (HINSTANCE hinstance, DWORD reason, LPVOID reserved)
+{
+ TRACE("%p,%x,%p\n", hinstance, reason, reserved);
+
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(hinstance);
+ DSM_hinstance = hinstance;
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
/* A helper function that looks up a destination identity in the active
source list */
static activeDS *TWAIN_LookupSource (const TW_IDENTITY *pDest)
@@ -132,6 +150,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);
@@ -142,6 +173,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/dll/win32/twain_32/twain_32.rc b/dll/win32/twain_32/twain_32.rc
index a09a0ee7e5..bf1cff4e7e 100644
--- a/dll/win32/twain_32/twain_32.rc
+++ b/dll/win32/twain_32/twain_32.rc
@@ -3,3 +3,6 @@
#define REACTOS_STR_INTERNAL_NAME "twain_32"
#define REACTOS_STR_ORIGINAL_FILENAME "twain_32.dll"
#include <reactos/version.rc>
+
+#include "twain.rc"
+
diff --git a/dll/win32/twain_32/twain_i.h b/dll/win32/twain_32/twain_i.h
index a170454a4e..32ebc2a221 100644
--- a/dll/win32/twain_32/twain_i.h
+++ b/dll/win32/twain_32/twain_i.h
@@ -32,8 +32,16 @@
#include <twain.h>
#include <wine/debug.h>
+#include <wine/list.h>
+
WINE_DEFAULT_DEBUG_CHANNEL(twain);
+struct pending_message
+{
+ struct list entry;
+ TW_UINT16 msg;
+};
+
/* internal information about an active data source */
typedef struct tagActiveDS
{
@@ -41,12 +49,17 @@ 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 */
activeDS *activeSources DECLSPEC_HIDDEN; /* list of active data sources */
+HINSTANCE DSM_hinstance DECLSPEC_HIDDEN;
+
/* Implementation of operation triplets (From Application to Source Manager) */
extern TW_UINT16 TWAIN_CloseDS
(pTW_IDENTITY pOrigin, TW_MEMREF pData) DECLSPEC_HIDDEN;
@@ -66,5 +79,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 /* _TWAIN32_H */
diff --git a/media/doc/README.WINE b/media/doc/README.WINE
index a4f3a1397d..5106521886 100644
--- a/media/doc/README.WINE
+++ b/media/doc/README.WINE
@@ -185,7 +185,7 @@ reactos/dll/win32/sxs # Synced to WineStaging-2.16
reactos/dll/win32/t2embed # Synced to WineStaging-2.9
reactos/dll/win32/tapi32 # Synced to WineStaging-2.9
reactos/dll/win32/traffic # Synced to WineStaging-2.9
-reactos/dll/win32/twain_32 # Synced to WineStaging-2.9
+reactos/dll/win32/twain_32 # Synced to Wine-3.0
reactos/dll/win32/updspapi # Synced to WineStaging-2.9
reactos/dll/win32/url # Synced to WineStaging-2.9
reactos/dll/win32/urlmon # Synced to WineStaging-2.16