[TWAIN_32] Sync with Wine 3.0. CORE-14225

This commit is contained in:
Amine Khaldi 2018-01-20 13:17:45 +01:00
parent b7250325e4
commit 0edcbac349
8 changed files with 321 additions and 12 deletions

View file

@ -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)

View file

@ -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)&param) == 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;
}

View file

@ -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

View file

@ -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
}

View file

@ -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);

View file

@ -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"

View file

@ -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 */

View file

@ -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