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);
38 static TW_UINT16 DSM_initialized; /* whether Source Manager is initialized */
39 static TW_UINT32 DSM_sourceId; /* source id generator */
40 static TW_UINT16 DSM_currentDevice; /* keep track of device during enumeration */
47 static int nrdevices = 0;
48 static struct all_devices *devices = NULL;
51 twain_add_onedriver(const char *dsname) {
54 TW_IDENTITY fakeOrigin;
58 hmod = LoadLibraryA(dsname);
60 ERR("Failed to load TWAIN Source %s\n", dsname);
63 dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry");
65 ERR("Failed to find DS_Entry() in TWAIN DS %s\n", dsname);
68 /* Loop to do multiple detects, mostly for sane.ds and gphoto2.ds */
72 sourceId.Id = DSM_sourceId;
73 sourceId.ProtocolMajor = TWON_PROTOCOLMAJOR;
74 sourceId.ProtocolMinor = TWON_PROTOCOLMINOR;
75 ret = dsEntry (&fakeOrigin, DG_CONTROL, DAT_IDENTITY, MSG_GET, &sourceId);
76 if (ret != TWRC_SUCCESS) {
77 ERR("Source->(DG_CONTROL,DAT_IDENTITY,MSG_GET) failed!\n");
80 TRACE("Manufacturer: %s\n", debugstr_a(sourceId.Manufacturer));
81 TRACE("ProductFamily: %s\n", debugstr_a(sourceId.ProductFamily));
82 TRACE("ProductName: %s\n", debugstr_a(sourceId.ProductName));
84 for (i=0;i<nrdevices;i++) {
85 if (!strcmp(sourceId.ProductName,devices[i].identity.ProductName))
91 devices = HeapReAlloc(GetProcessHeap(), 0, devices, sizeof(devices[0])*(nrdevices+1));
93 devices = HeapAlloc(GetProcessHeap(), 0, sizeof(devices[0]));
94 if ((devices[nrdevices].modname = HeapAlloc(GetProcessHeap(), 0, strlen(dsname) + 1)))
95 lstrcpyA(devices[nrdevices].modname, dsname);
96 devices[nrdevices].identity = sourceId;
103 static int detectionrun = 0;
106 twain_autodetect(void) {
107 if (detectionrun) return;
110 twain_add_onedriver("sane.ds");
111 twain_add_onedriver("gphoto2.ds");
113 twain_add_onedriver("c:\\windows\\Twain_32\\Largan\\sp503a.ds");
114 twain_add_onedriver("c:\\windows\\Twain_32\\vivicam10\\vivicam10.ds");
115 twain_add_onedriver("c:\\windows\\Twain_32\\ws30slim\\sp500a.ds");
119 /* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
120 TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
122 TW_UINT16 twRC = TWRC_SUCCESS;
123 pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
124 activeDS *currentDS = NULL, *prevDS = NULL;
126 TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
128 for (currentDS = activeSources; currentDS; currentDS = currentDS->next) {
129 if (currentDS->identity.Id == pIdentity->Id)
134 DSM_twCC = TWCC_NODS;
137 twRC = currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
138 /* This causes crashes due to still open Windows, so leave out for now.
139 * FreeLibrary (currentDS->hmod);
142 prevDS->next = currentDS->next;
144 activeSources = currentDS->next;
145 HeapFree (GetProcessHeap(), 0, currentDS);
146 if (twRC == TWRC_SUCCESS)
147 DSM_twCC = TWCC_SUCCESS;
148 else /* FIXME: unclear how to get TWCC */
149 DSM_twCC = TWCC_SEQERROR;
153 /* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
154 TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
156 pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
158 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
159 DSM_twCC = TWCC_NODS;
163 *pSourceIdentity = devices[0].identity;
164 DSM_twCC = TWCC_SUCCESS;
168 /* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
169 TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
171 pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
173 TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
176 TRACE ("no entries found.\n");
177 DSM_twCC = TWCC_NODS;
180 DSM_currentDevice = 0;
181 *pSourceIdentity = devices[DSM_currentDevice++].identity;
185 /* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
186 TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
188 pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
190 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
191 if (!nrdevices || (DSM_currentDevice == nrdevices)) {
192 DSM_twCC = TWCC_SUCCESS;
193 return TWRC_ENDOFLIST;
195 *pSourceIdentity = devices[DSM_currentDevice++].identity;
199 /* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
200 TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
203 pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
205 const char *modname = NULL;
208 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
209 TRACE("pIdentity is %s\n", pIdentity->ProductName);
210 if (DSM_currentState != 3) {
211 FIXME("seq error\n");
212 DSM_twCC = TWCC_SEQERROR;
218 DSM_twCC = TWCC_NODS;
222 if (pIdentity->ProductName[0] != '\0') {
223 /* Make sure the source to be opened exists in the device list */
224 for (i = 0; i<nrdevices; i++)
225 if (!strcmp (devices[i].identity.ProductName, pIdentity->ProductName))
229 } /* else use the first device */
231 /* the source is found in the device list */
232 newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
234 DSM_twCC = TWCC_LOWMEMORY;
235 FIXME("Out of memory.\n");
238 hmod = LoadLibraryA(devices[i].modname);
240 ERR("Failed to load TWAIN Source %s\n", modname);
241 DSM_twCC = TWCC_OPERATIONERROR;
242 HeapFree(GetProcessHeap(), 0, newSource);
245 newSource->hmod = hmod;
246 newSource->dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry");
247 if (TWRC_SUCCESS != newSource->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, pIdentity)) {
248 DSM_twCC = TWCC_OPERATIONERROR;
249 HeapFree(GetProcessHeap(), 0, newSource);
252 /* Assign name and id for the opened data source */
253 pIdentity->Id = DSM_sourceId ++;
254 /* add the data source to an internal active source list */
255 newSource->next = activeSources;
256 newSource->identity.Id = pIdentity->Id;
257 strcpy (newSource->identity.ProductName, pIdentity->ProductName);
258 activeSources = newSource;
259 DSM_twCC = TWCC_SUCCESS;
263 /* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
264 TW_UINT16 TWAIN_UserSelect (pTW_IDENTITY pOrigin, TW_MEMREF pData)
266 pTW_IDENTITY selected = (pTW_IDENTITY)pData;
269 DSM_twCC = TWCC_OPERATIONERROR;
272 *selected = devices[0].identity;
273 DSM_twCC = TWCC_SUCCESS;
277 /* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
278 TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
280 activeDS *currentDS = activeSources, *nextDS;
282 TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");
284 if (DSM_currentState == 3)
286 DSM_initialized = FALSE;
287 DSM_currentState = 2;
289 /* If there are data sources still open, close them now. */
290 while (currentDS != NULL)
292 nextDS = currentDS->next;
293 currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
294 HeapFree (GetProcessHeap(), 0, currentDS);
297 activeSources = NULL;
298 DSM_twCC = TWCC_SUCCESS;
301 DSM_twCC = TWCC_SEQERROR;
306 /* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
307 TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
309 TW_UINT16 twRC = TWRC_SUCCESS;
311 TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
312 if (DSM_currentState == 2) {
313 if (!DSM_initialized) {
314 DSM_currentDevice = 0;
315 DSM_initialized = TRUE;
317 DSM_currentState = 3;
318 DSM_twCC = TWCC_SUCCESS;
321 /* operation invoked in invalid state */
322 DSM_twCC = TWCC_SEQERROR;
328 /* DG_CONTROL/DAT_STATUS/MSG_GET */
329 TW_UINT16 TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin, TW_MEMREF pData)
331 pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
333 TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
335 pSourceStatus->ConditionCode = DSM_twCC;
336 DSM_twCC = TWCC_SUCCESS; /* clear the condition code */