* TWAIN32 Source Manager
*
* Copyright 2000 Corel Corporation
+ * Copyright 2006 Marcus Meissner
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
*
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-//#include "config.h"
-
#include <stdlib.h>
#include <stdarg.h>
+#include <stdio.h>
-#define NONAMELESSUNION
-#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
+#include "winuser.h"
#include "twain.h"
#include "twain_i.h"
+#include "resource.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(twain);
-/* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
-TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
-{
-#ifndef HAVE_SANE
- DSM_twCC = TWCC_NODS;
- return TWRC_FAILURE;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS;
- pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
- activeDS *currentDS = NULL, *prevDS = NULL;
+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;
+ TW_IDENTITY identity;
+};
+
+static int nrdevices = 0;
+static struct all_devices *devices = NULL;
+
+static void
+twain_add_onedriver(const char *dsname) {
+ HMODULE hmod;
+ DSENTRYPROC dsEntry;
+ TW_IDENTITY fakeOrigin;
+ TW_IDENTITY sourceId;
+ TW_UINT16 ret;
+
+ hmod = LoadLibraryA(dsname);
+ if (!hmod) {
+ ERR("Failed to load TWAIN Source %s\n", debugstr_a(dsname));
+ return;
+ }
+ dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry");
+ if (!dsEntry) {
+ ERR("Failed to find DS_Entry() in TWAIN DS %s\n", debugstr_a(dsname));
+ return;
+ }
+ /* Loop to do multiple detects, mostly for sane.ds and gphoto2.ds */
+ do {
+ int i;
+
+ sourceId.Id = DSM_sourceId;
+ sourceId.ProtocolMajor = TWON_PROTOCOLMAJOR;
+ sourceId.ProtocolMinor = TWON_PROTOCOLMINOR;
+ ret = dsEntry (&fakeOrigin, DG_CONTROL, DAT_IDENTITY, MSG_GET, &sourceId);
+ if (ret != TWRC_SUCCESS) {
+ ERR("Source->(DG_CONTROL,DAT_IDENTITY,MSG_GET) failed!\n");
+ break;
+ }
+ TRACE("Manufacturer: %s\n", debugstr_a(sourceId.Manufacturer));
+ TRACE("ProductFamily: %s\n", debugstr_a(sourceId.ProductFamily));
+ TRACE("ProductName: %s\n", debugstr_a(sourceId.ProductName));
+
+ for (i=0;i<nrdevices;i++) {
+ if (!strcmp(sourceId.ProductName,devices[i].identity.ProductName))
+ break;
+ }
+ if (i < nrdevices)
+ break;
+ if (nrdevices)
+ devices = HeapReAlloc(GetProcessHeap(), 0, devices, sizeof(devices[0])*(nrdevices+1));
+ else
+ devices = HeapAlloc(GetProcessHeap(), 0, sizeof(devices[0]));
+ if ((devices[nrdevices].modname = HeapAlloc(GetProcessHeap(), 0, strlen(dsname) + 1)))
+ lstrcpyA(devices[nrdevices].modname, dsname);
+ devices[nrdevices].identity = sourceId;
+ nrdevices++;
+ DSM_sourceId++;
+ } while (1);
+ FreeLibrary (hmod);
+}
- TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
+static BOOL detectionrun = FALSE;
- for (currentDS = activeSources; currentDS; currentDS = currentDS->next)
- {
- if (currentDS->identity.Id == pIdentity->Id)
- break;
- prevDS = currentDS;
- }
- if (currentDS)
- {
- /* Only valid to close a data source if it is in state 4 */
- if (currentDS->currentState == 4)
- {
- sane_close (currentDS->deviceHandle);
- /* remove the data source from active data source list */
- if (prevDS)
- prevDS->next = currentDS->next;
- else
- activeSources = currentDS->next;
- HeapFree (GetProcessHeap(), 0, currentDS);
- twRC = TWRC_SUCCESS;
- DSM_twCC = TWCC_SUCCESS;
- }
- else
- {
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_SEQERROR;
- }
- }
- else
- {
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_NODS;
- }
+static void
+twain_autodetect(void) {
+ if (detectionrun) return;
+ detectionrun = TRUE;
- return twRC;
+ twain_add_onedriver("sane.ds");
+ twain_add_onedriver("gphoto2.ds");
+#if 0
+ twain_add_onedriver("c:\\windows\\Twain_32\\Largan\\sp503a.ds");
+ twain_add_onedriver("c:\\windows\\Twain_32\\vivicam10\\vivicam10.ds");
+ twain_add_onedriver("c:\\windows\\Twain_32\\ws30slim\\sp500a.ds");
#endif
}
-/* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
-TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
+/* 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)
{
-#ifndef HAVE_SANE
- DSM_twCC = TWCC_NODS;
- return TWRC_FAILURE;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS;
- pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
+ struct pending_message *message;
- TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
+ TRACE ("DG_CONTROL/DAT_NULL MSG=%i\n", MSG);
- if (!device_list)
+ if (MSG != MSG_CLOSEDSREQ &&
+ MSG != MSG_DEVICEEVENT &&
+ MSG != MSG_XFERREADY)
{
- if ((sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
- {
- DSM_twCC = TWCC_NODS;
- return TWRC_FAILURE;
- }
+ DSM_twCC = TWCC_BADPROTOCOL;
+ return TWRC_FAILURE;
}
- /* FIXME: the default device is not necessarily the first device. *
- * Users should be able to choose the default device */
- if (device_list && device_list[0])
- {
- pSourceIdentity->Id = DSM_sourceId ++;
- strcpy (pSourceIdentity->ProductName, device_list[0]->name);
- strcpy (pSourceIdentity->Manufacturer, device_list[0]->vendor);
- strcpy (pSourceIdentity->ProductFamily, device_list[0]->model);
- pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
- pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
-
- twRC = TWRC_SUCCESS;
- DSM_twCC = TWCC_SUCCESS;
- }
- else
+ message = HeapAlloc(GetProcessHeap(), 0, sizeof(*message));
+ if (!message)
{
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_NODS;
+ DSM_twCC = TWCC_LOWMEMORY;
+ return TWRC_FAILURE;
}
- return twRC;
-#endif
+ 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;
}
-/* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
-TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
+/* Filters MSG_PROCESSEVENT messages before reaching the data source */
+TW_UINT16 TWAIN_ProcessEvent (pTW_IDENTITY pOrigin, activeDS *pSource, TW_MEMREF pData)
{
-#ifndef HAVE_SANE
- DSM_twCC = TWCC_NODS;
- return TWRC_FAILURE;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS;
- pTW_IDENTITY pSourceIdentity;/* = (pTW_IDENTITY) pData;*/
- SANE_Status status;
-
- TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
-
- status = sane_get_devices (&device_list, SANE_FALSE);
- if (status == SANE_STATUS_GOOD)
+ 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 (device_list[0])
+ if (!list_empty (&pSource->pending_messages))
{
- pSourceIdentity->Id = DSM_sourceId ++;
- strcpy (pSourceIdentity->ProductName, device_list[0]->name);
- strcpy (pSourceIdentity->Manufacturer, device_list[0]->vendor);
- strcpy (pSourceIdentity->ProductFamily, device_list[0]->model);
- pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
- pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
+ 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);
}
- DSM_currentDevice = 1;
- twRC = TWRC_SUCCESS;
- DSM_twCC = TWCC_SUCCESS;
- }
- else if (status == SANE_STATUS_NO_MEM)
- {
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_LOWMEMORY;
+ else
+ event->TWMessage = MSG_NULL;
+ result = TWRC_DSEVENT;
}
- else
+
+ if (msg->hwnd)
{
- WARN("sane_get_devices() failed: %s\n", sane_strstatus (status));
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_NODS;
+ 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 twRC;
-#endif
+ return result;
}
-/* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
-TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
+/* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
+TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
-#ifndef HAVE_SANE
- DSM_twCC = TWCC_SUCCESS;
- return TWRC_ENDOFLIST;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS;
- pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
+ TW_UINT16 twRC = TWRC_SUCCESS;
+ pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
+ activeDS *currentDS = NULL, *prevDS = NULL;
+
+ TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
+
+ for (currentDS = activeSources; currentDS; currentDS = currentDS->next) {
+ if (currentDS->identity.Id == pIdentity->Id)
+ break;
+ prevDS = currentDS;
+ }
+ if (!currentDS) {
+ DSM_twCC = TWCC_NODS;
+ return TWRC_FAILURE;
+ }
+ twRC = currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
+ /* This causes crashes due to still open Windows, so leave out for now.
+ * FreeLibrary (currentDS->hmod);
+ */
+ if (prevDS)
+ prevDS->next = currentDS->next;
+ else
+ activeSources = currentDS->next;
+ HeapFree (GetProcessHeap(), 0, currentDS);
+ if (twRC == TWRC_SUCCESS)
+ DSM_twCC = TWCC_SUCCESS;
+ else /* FIXME: unclear how to get TWCC */
+ DSM_twCC = TWCC_SEQERROR;
+ return twRC;
+}
- TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
+/* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
+TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
+{
+ pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
+
+ TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
+ DSM_twCC = TWCC_NODS;
+ twain_autodetect();
+ if (!nrdevices)
+ return TWRC_FAILURE;
+ *pSourceIdentity = devices[0].identity;
+ DSM_twCC = TWCC_SUCCESS;
+ return TWRC_SUCCESS;
+}
- if (device_list && device_list[DSM_currentDevice])
- {
- pSourceIdentity->Id = DSM_sourceId ++;
- strcpy (pSourceIdentity->ProductName, device_list[DSM_currentDevice]->name);
- strcpy (pSourceIdentity->Manufacturer, device_list[DSM_currentDevice]->vendor);
- strcpy (pSourceIdentity->ProductFamily, device_list[DSM_currentDevice]->model);
- pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
- pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
- DSM_currentDevice ++;
-
- twRC = TWRC_SUCCESS;
- DSM_twCC = TWCC_SUCCESS;
- }
- else
- {
- DSM_twCC = TWCC_SUCCESS;
- twRC = TWRC_ENDOFLIST;
- }
+/* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
+TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
+{
+ pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
+
+ TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
+ twain_autodetect();
+ if (!nrdevices) {
+ TRACE ("no entries found.\n");
+ DSM_twCC = TWCC_NODS;
+ return TWRC_FAILURE;
+ }
+ DSM_currentDevice = 0;
+ *pSourceIdentity = devices[DSM_currentDevice++].identity;
+ return TWRC_SUCCESS;
+}
- return twRC;
-#endif
+/* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
+TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
+{
+ pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
+
+ TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
+ if (!nrdevices || (DSM_currentDevice == nrdevices)) {
+ DSM_twCC = TWCC_SUCCESS;
+ return TWRC_ENDOFLIST;
+ }
+ *pSourceIdentity = devices[DSM_currentDevice++].identity;
+ return TWRC_SUCCESS;
}
/* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
-#ifndef HAVE_SANE
- DSM_twCC = TWCC_NODS;
- return TWRC_FAILURE;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS, i = 0;
- pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
- activeDS *newSource;
- SANE_Status status;
-
- TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
-
- if (DSM_currentState != 3)
- {
- DSM_twCC = TWCC_SEQERROR;
- return TWRC_FAILURE;
- }
+ TW_UINT16 i = 0;
+ pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
+ activeDS *newSource;
+ const char *modname = NULL;
+ HMODULE hmod;
+
+ TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
+ TRACE("pIdentity is %s\n", pIdentity->ProductName);
+ if (!DSM_initialized) {
+ FIXME("seq error\n");
+ DSM_twCC = TWCC_SEQERROR;
+ return TWRC_FAILURE;
+ }
+ twain_autodetect();
+ if (!nrdevices) {
+ FIXME("no devs.\n");
+ DSM_twCC = TWCC_NODS;
+ return TWRC_FAILURE;
+ }
+
+ if (pIdentity->ProductName[0] != '\0') {
+ /* Make sure the source to be opened exists in the device list */
+ for (i = 0; i<nrdevices; i++)
+ if (!strcmp (devices[i].identity.ProductName, pIdentity->ProductName))
+ break;
+ if (i == nrdevices)
+ i = 0;
+ } /* else use the first device */
+
+ /* the source is found in the device list */
+ newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
+ if (!newSource) {
+ DSM_twCC = TWCC_LOWMEMORY;
+ FIXME("Out of memory.\n");
+ return TWRC_FAILURE;
+ }
+ hmod = LoadLibraryA(devices[i].modname);
+ if (!hmod) {
+ ERR("Failed to load TWAIN Source %s\n", debugstr_a(modname));
+ DSM_twCC = TWCC_OPERATIONERROR;
+ HeapFree(GetProcessHeap(), 0, newSource);
+ return TWRC_FAILURE;
+ }
+ 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;
+ }
+ /* 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;
+}
- if (!device_list &&
- (sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
- {
- DSM_twCC = TWCC_NODS;
- return TWRC_FAILURE;
- }
+typedef struct {
+ pTW_IDENTITY origin;
+ pTW_IDENTITY result;
+} userselect_data;
- if (pIdentity->ProductName[0] != '\0')
+static INT_PTR CALLBACK userselect_dlgproc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
{
- /* Make sure the source to be open exists in the device list */
- for (i = 0; device_list[i]; i ++)
+ 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++)
{
- if (strcmp (device_list[i]->name, pIdentity->ProductName) == 0)
- break;
+ 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 (device_list[i])
- {
- /* the source is found in the device list */
- newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
- if (newSource)
+ if (any_devices)
{
- status = sane_open(device_list[i]->name,&newSource->deviceHandle);
- if (status == SANE_STATUS_GOOD)
- {
- /* Assign name and id for the opened data source */
- strcpy (pIdentity->ProductName, device_list[i]->name);
- 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);
- newSource->currentState = 4; /*transition into state 4*/
- newSource->twCC = TWCC_SUCCESS;
- activeSources = newSource;
- twRC = TWRC_SUCCESS;
- DSM_twCC = TWCC_SUCCESS;
- }
- else
- {
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_OPERATIONERROR;
- }
+ EnableWindow(GetDlgItem(hwnd, IDOK), TRUE);
+
+ /* FIXME: Select the supplied product name or default source. */
+ SendMessageW(sourcelist, LB_SETCURSEL, 0, 0);
}
- else
+
+ return TRUE;
+ }
+ case WM_CLOSE:
+ EndDialog(hwnd, 0);
+ return TRUE;
+ case WM_COMMAND:
+ if (wparam == MAKEWPARAM(IDCANCEL, BN_CLICKED))
{
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_LOWMEMORY;
+ EndDialog(hwnd, 0);
+ return TRUE;
}
- }
- else
- {
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_NODS;
- }
+ 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;
- return twRC;
-#endif
+ 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)
{
-#ifndef HAVE_SANE
- return TWRC_SUCCESS;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS;
+ userselect_data param = {pOrigin, pData};
+ HWND parent = DSM_parent;
+
+ TRACE("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT SupportedGroups=0x%x ProductName=%s\n",
+ pOrigin->SupportedGroups, wine_dbgstr_a(param.result->ProductName));
+
+ twain_autodetect();
- TRACE("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT\n");
+ if (!IsWindow(parent))
+ parent = NULL;
- /* FIXME: we should replace xscanimage with our own User Select UI */
- system("xscanimage");
+ 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;
-#endif
+ return TWRC_SUCCESS;
}
/* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
-#ifndef HAVE_SANE
- return TWRC_FAILURE;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS;
activeDS *currentDS = activeSources, *nextDS;
TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");
- if (DSM_currentState == 3)
+ if (DSM_initialized)
{
- sane_exit ();
DSM_initialized = FALSE;
- DSM_parentHWND = 0;
- DSM_currentState = 2;
/* If there are data sources still open, close them now. */
while (currentDS != NULL)
{
nextDS = currentDS->next;
- sane_close (currentDS->deviceHandle);
+ currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
HeapFree (GetProcessHeap(), 0, currentDS);
currentDS = nextDS;
}
activeSources = NULL;
+ DSM_parent = NULL;
DSM_twCC = TWCC_SUCCESS;
- twRC = TWRC_SUCCESS;
- }
- else
- {
+ return TWRC_SUCCESS;
+ } else {
DSM_twCC = TWCC_SEQERROR;
- twRC = TWRC_FAILURE;
+ return TWRC_FAILURE;
}
-
- return twRC;
-#endif
}
/* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
-#ifndef HAVE_SANE
- return TWRC_FAILURE;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS;
- SANE_Status status;
- SANE_Int version_code;
-
- TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
-
- if (DSM_currentState == 2)
- {
- if (!DSM_initialized)
- {
- DSM_initialized = TRUE;
- status = sane_init (&version_code, NULL);
- device_list = NULL;
- DSM_currentDevice = 0;
- DSM_sourceId = 0;
- }
- DSM_parentHWND = *(TW_HANDLE*)pData;
- DSM_currentState = 3; /* transition to state 3 */
- DSM_twCC = TWCC_SUCCESS;
- twRC = TWRC_SUCCESS;
- }
- else
- {
- /* operation invoked in invalid state */
- DSM_twCC = TWCC_SEQERROR;
- twRC = TWRC_FAILURE;
- }
-
- return twRC;
-#endif
+ TW_UINT16 twRC = TWRC_SUCCESS;
+
+ 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;
+ twRC = TWRC_SUCCESS;
+ } else {
+ /* operation invoked in invalid state */
+ DSM_twCC = TWCC_SEQERROR;
+ twRC = TWRC_FAILURE;
+ }
+ DSM_parent = (HWND)pData;
+ return twRC;
}
/* DG_CONTROL/DAT_STATUS/MSG_GET */
TW_UINT16 TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
- pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
+ pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
- TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
+ TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
- pSourceStatus->ConditionCode = DSM_twCC;
- DSM_twCC = TWCC_SUCCESS; /* clear the condition code */
-
- return TWRC_SUCCESS;
+ pSourceStatus->ConditionCode = DSM_twCC;
+ DSM_twCC = TWCC_SUCCESS; /* clear the condition code */
+ return TWRC_SUCCESS;
}