2 * TWAIN32 Source Manager
4 * Copyright 2000 Corel Corporation
5 * Copyright 2006 Marcus Meissner
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(twain);
43 static int nrdevices = 0;
44 static struct all_devices *devices = NULL;
47 twain_add_onedriver(const char *dsname) {
50 TW_IDENTITY fakeOrigin;
54 hmod = LoadLibraryA(dsname);
56 ERR("Failed to load TWAIN Source %s\n", dsname);
59 dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry");
61 ERR("Failed to find DS_Entry() in TWAIN DS %s\n", dsname);
64 /* Loop to do multiple detects, mostly for sane.ds and gphoto2.ds */
68 sourceId.Id = DSM_sourceId;
69 sourceId.ProtocolMajor = TWON_PROTOCOLMAJOR;
70 sourceId.ProtocolMinor = TWON_PROTOCOLMINOR;
71 ret = dsEntry (&fakeOrigin, DG_CONTROL, DAT_IDENTITY, MSG_GET, &sourceId);
72 if (ret != TWRC_SUCCESS) {
73 ERR("Source->(DG_CONTROL,DAT_IDENTITY,MSG_GET) failed!\n");
76 TRACE("Manufacturer: %s\n", debugstr_a(sourceId.Manufacturer));
77 TRACE("ProductFamily: %s\n", debugstr_a(sourceId.ProductFamily));
78 TRACE("ProductName: %s\n", debugstr_a(sourceId.ProductName));
80 for (i=0;i<nrdevices;i++) {
81 if (!strcmp(sourceId.ProductName,devices[i].identity.ProductName))
87 devices = realloc(devices, sizeof(devices[0])*(nrdevices+1));
89 devices = malloc(sizeof(devices[0]));
90 devices[nrdevices].modname = strdup(dsname);
91 memcpy (&devices[nrdevices].identity, &sourceId, sizeof(sourceId));
98 static int detectionrun = 0;
101 twain_autodetect(void) {
102 if (detectionrun) return;
105 twain_add_onedriver("gphoto2.ds");
106 twain_add_onedriver("sane.ds");
108 twain_add_onedriver("c:\\windows\\Twain_32\\Largan\\sp503a.ds");
109 twain_add_onedriver("c:\\windows\\Twain_32\\vivicam10\\vivicam10.ds");
110 twain_add_onedriver("c:\\windows\\Twain_32\\ws30slim\\sp500a.ds");
114 /* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
115 TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
117 TW_UINT16 twRC = TWRC_SUCCESS;
118 pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
119 activeDS *currentDS = NULL, *prevDS = NULL;
121 TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
123 for (currentDS = activeSources; currentDS; currentDS = currentDS->next) {
124 if (currentDS->identity.Id == pIdentity->Id)
129 DSM_twCC = TWCC_NODS;
132 twRC = currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
133 /* This causes crashes due to still open Windows, so leave out for now.
134 * FreeLibrary (currentDS->hmod);
137 prevDS->next = currentDS->next;
139 activeSources = currentDS->next;
140 HeapFree (GetProcessHeap(), 0, currentDS);
141 if (twRC == TWRC_SUCCESS)
142 DSM_twCC = TWCC_SUCCESS;
143 else /* FIXME: unclear how to get TWCC */
144 DSM_twCC = TWCC_SEQERROR;
148 /* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
149 TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
151 pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
153 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
154 DSM_twCC = TWCC_NODS;
158 memcpy (pSourceIdentity, &devices[0].identity, sizeof(TW_IDENTITY));
162 /* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
163 TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
165 pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
167 TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
170 TRACE ("no entries found.\n");
171 DSM_twCC = TWCC_SUCCESS;
172 return TWRC_ENDOFLIST;
174 DSM_currentDevice = 0;
175 memcpy (pSourceIdentity, &devices[DSM_currentDevice++].identity, sizeof(TW_IDENTITY));
179 /* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
180 TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
182 pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
184 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
185 if (!nrdevices || (DSM_currentDevice == nrdevices)) {
186 DSM_twCC = TWCC_SUCCESS;
187 return TWRC_ENDOFLIST;
189 memcpy (pSourceIdentity, &devices[DSM_currentDevice++].identity, sizeof(TW_IDENTITY));
193 /* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
194 TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
197 pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
199 const char *modname = NULL;
202 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
203 TRACE("pIdentity is %s\n", pIdentity->ProductName);
204 if (DSM_currentState != 3) {
205 FIXME("seq errror\n");
206 DSM_twCC = TWCC_SEQERROR;
212 DSM_twCC = TWCC_NODS;
216 if (pIdentity->ProductName[0] != '\0') {
217 /* Make sure the source to be opened exists in the device list */
218 for (i = 0; i<nrdevices; i++)
219 if (!strcmp (devices[i].identity.ProductName, pIdentity->ProductName))
223 } /* else use the first device */
225 /* the source is found in the device list */
226 newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
228 DSM_twCC = TWCC_LOWMEMORY;
229 FIXME("Out of memory.\n");
232 hmod = LoadLibraryA(devices[i].modname);
234 ERR("Failed to load TWAIN Source %s\n", modname);
235 DSM_twCC = TWCC_OPERATIONERROR;
236 HeapFree(GetProcessHeap(), 0, newSource);
239 newSource->hmod = hmod;
240 newSource->dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry");
241 if (TWRC_SUCCESS != newSource->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, pIdentity)) {
242 DSM_twCC = TWCC_OPERATIONERROR;
243 HeapFree(GetProcessHeap(), 0, newSource);
246 /* Assign name and id for the opened data source */
247 pIdentity->Id = DSM_sourceId ++;
248 /* add the data source to an internal active source list */
249 newSource->next = activeSources;
250 newSource->identity.Id = pIdentity->Id;
251 strcpy (newSource->identity.ProductName, pIdentity->ProductName);
252 activeSources = newSource;
253 DSM_twCC = TWCC_SUCCESS;
257 /* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
258 TW_UINT16 TWAIN_UserSelect (pTW_IDENTITY pOrigin, TW_MEMREF pData)
260 pTW_IDENTITY selected = (pTW_IDENTITY)pData;
263 DSM_twCC = TWCC_OPERATIONERROR;
266 memcpy (selected, &devices[0].identity, sizeof(TW_IDENTITY));
267 DSM_twCC = TWCC_SUCCESS;
271 /* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
272 TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
274 activeDS *currentDS = activeSources, *nextDS;
276 TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");
278 if (DSM_currentState == 3)
280 DSM_initialized = FALSE;
281 DSM_currentState = 2;
283 /* If there are data sources still open, close them now. */
284 while (currentDS != NULL)
286 nextDS = currentDS->next;
287 currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
288 HeapFree (GetProcessHeap(), 0, currentDS);
291 activeSources = NULL;
292 DSM_twCC = TWCC_SUCCESS;
295 DSM_twCC = TWCC_SEQERROR;
300 /* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
301 TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
303 TW_UINT16 twRC = TWRC_SUCCESS;
305 TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
306 if (DSM_currentState == 2) {
307 if (!DSM_initialized) {
308 DSM_currentDevice = 0;
309 DSM_initialized = TRUE;
311 DSM_currentState = 3;
312 DSM_twCC = TWCC_SUCCESS;
315 /* operation invoked in invalid state */
316 DSM_twCC = TWCC_SEQERROR;
322 /* DG_CONTROL/DAT_STATUS/MSG_GET */
323 TW_UINT16 TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin, TW_MEMREF pData)
325 pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
327 TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
329 pSourceStatus->ConditionCode = DSM_twCC;
330 DSM_twCC = TWCC_SUCCESS; /* clear the condition code */