msvcrt: Added _swscanf_l implementation.
[wine] / dlls / twain_32 / dsm_ctrl.c
1 /*
2  * TWAIN32 Source Manager
3  *
4  * Copyright 2000 Corel Corporation
5  * Copyright 2006 Marcus Meissner
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
30 #include "windef.h"
31 #include "winbase.h"
32 #include "twain.h"
33 #include "twain_i.h"
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(twain);
37
38 struct all_devices {
39         char            *modname;
40         TW_IDENTITY     identity;
41 };
42
43 static int nrdevices = 0;
44 static struct all_devices *devices = NULL;
45
46 static void
47 twain_add_onedriver(const char *dsname) {
48         HMODULE         hmod;
49         DSENTRYPROC     dsEntry;
50         TW_IDENTITY     fakeOrigin;
51         TW_IDENTITY     sourceId;
52         TW_UINT16       ret;
53
54         hmod = LoadLibraryA(dsname);
55         if (!hmod) {
56                 ERR("Failed to load TWAIN Source %s\n", dsname);
57                 return;
58         }
59         dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry"); 
60         if (!dsEntry) {
61                 ERR("Failed to find DS_Entry() in TWAIN DS %s\n", dsname);
62                 return;
63         }
64         /* Loop to do multiple detects, mostly for sane.ds and gphoto2.ds */
65         do {
66                 int i;
67
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");
74                         return;
75                 }
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));
79
80                 for (i=0;i<nrdevices;i++) {
81                         if (!strcmp(sourceId.ProductName,devices[i].identity.ProductName))
82                                 break;
83                 }
84                 if (i < nrdevices)
85                         break;
86                 if (nrdevices)
87                         devices = HeapReAlloc(GetProcessHeap(), 0, devices, sizeof(devices[0])*(nrdevices+1));
88                 else
89                         devices = HeapAlloc(GetProcessHeap(), 0, sizeof(devices[0]));
90                 if ((devices[nrdevices].modname = HeapAlloc(GetProcessHeap(), 0, strlen(dsname) + 1)))
91                         lstrcpyA(devices[nrdevices].modname, dsname);
92                 devices[nrdevices].identity = sourceId;
93                 nrdevices++;
94                 DSM_sourceId++;
95         } while (1);
96         FreeLibrary (hmod);
97 }
98
99 static int detectionrun = 0;
100
101 static void
102 twain_autodetect(void) {
103         if (detectionrun) return;
104         detectionrun = 1;
105
106         twain_add_onedriver("sane.ds");
107         twain_add_onedriver("gphoto2.ds");
108 #if 0
109         twain_add_onedriver("c:\\windows\\Twain_32\\Largan\\sp503a.ds");
110         twain_add_onedriver("c:\\windows\\Twain_32\\vivicam10\\vivicam10.ds");
111         twain_add_onedriver("c:\\windows\\Twain_32\\ws30slim\\sp500a.ds");
112 #endif
113 }
114
115 /* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
116 TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
117 {
118         TW_UINT16 twRC = TWRC_SUCCESS;
119         pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
120         activeDS *currentDS = NULL, *prevDS = NULL;
121
122         TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
123
124         for (currentDS = activeSources; currentDS; currentDS = currentDS->next) {
125                 if (currentDS->identity.Id == pIdentity->Id)
126                         break;
127                 prevDS = currentDS;
128         }
129         if (!currentDS) {
130                 DSM_twCC = TWCC_NODS;
131                 return TWRC_FAILURE;
132         }
133         twRC = currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
134         /* This causes crashes due to still open Windows, so leave out for now.
135          * FreeLibrary (currentDS->hmod);
136          */
137         if (prevDS)
138                 prevDS->next = currentDS->next;
139         else
140                 activeSources = currentDS->next;
141         HeapFree (GetProcessHeap(), 0, currentDS);
142         if (twRC == TWRC_SUCCESS)
143                 DSM_twCC = TWCC_SUCCESS;
144         else /* FIXME: unclear how to get TWCC */
145                 DSM_twCC = TWCC_SEQERROR;
146         return twRC;
147 }
148
149 /* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
150 TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
151 {
152         pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
153
154         TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
155         DSM_twCC = TWCC_NODS;
156         twain_autodetect();
157         if (!nrdevices)
158                 return TWRC_FAILURE;
159         *pSourceIdentity = devices[0].identity;
160         DSM_twCC = TWCC_SUCCESS;
161         return TWRC_SUCCESS;
162 }
163
164 /* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
165 TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
166 {
167         pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
168
169         TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
170         twain_autodetect();
171         if (!nrdevices) {
172                 TRACE ("no entries found.\n");
173                 DSM_twCC = TWCC_NODS;
174                 return TWRC_FAILURE;
175         }
176         DSM_currentDevice = 0;
177         *pSourceIdentity = devices[DSM_currentDevice++].identity;
178         return TWRC_SUCCESS;
179 }
180
181 /* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
182 TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
183 {
184         pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
185
186         TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
187         if (!nrdevices || (DSM_currentDevice == nrdevices)) {
188                 DSM_twCC = TWCC_SUCCESS;
189                 return TWRC_ENDOFLIST;
190         }
191         *pSourceIdentity = devices[DSM_currentDevice++].identity;
192         return TWRC_SUCCESS;
193 }
194
195 /* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
196 TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
197 {
198         TW_UINT16 i = 0;
199         pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
200         activeDS *newSource;
201         const char *modname = NULL;
202         HMODULE hmod;
203
204         TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
205         TRACE("pIdentity is %s\n", pIdentity->ProductName);
206         if (DSM_currentState != 3) {
207                 FIXME("seq error\n");
208                 DSM_twCC = TWCC_SEQERROR;
209                 return TWRC_FAILURE;
210         }
211         twain_autodetect();
212         if (!nrdevices) {
213                 FIXME("no devs.\n");
214                 DSM_twCC = TWCC_NODS;
215                 return TWRC_FAILURE;
216         }
217
218         if (pIdentity->ProductName[0] != '\0') {
219                 /* Make sure the source to be opened exists in the device list */
220                 for (i = 0; i<nrdevices; i++)
221                         if (!strcmp (devices[i].identity.ProductName, pIdentity->ProductName))
222                                 break;
223                 if (i == nrdevices)
224                         i = 0;
225         } /* else use the first device */
226
227         /* the source is found in the device list */
228         newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
229         if (!newSource) {
230                 DSM_twCC = TWCC_LOWMEMORY;
231                 FIXME("Out of memory.\n");
232                 return TWRC_FAILURE;
233         }
234         hmod = LoadLibraryA(devices[i].modname);
235         if (!hmod) {
236                 ERR("Failed to load TWAIN Source %s\n", modname);
237                 DSM_twCC = TWCC_OPERATIONERROR;
238                 HeapFree(GetProcessHeap(), 0, newSource);
239                 return TWRC_FAILURE;
240         }
241         newSource->hmod = hmod; 
242         newSource->dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry"); 
243         if (TWRC_SUCCESS != newSource->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, pIdentity)) {
244                 DSM_twCC = TWCC_OPERATIONERROR;
245                 HeapFree(GetProcessHeap(), 0, newSource);
246                 return TWRC_FAILURE;
247         }
248         /* Assign name and id for the opened data source */
249         pIdentity->Id = DSM_sourceId ++;
250         /* add the data source to an internal active source list */
251         newSource->next = activeSources;
252         newSource->identity.Id = pIdentity->Id;
253         strcpy (newSource->identity.ProductName, pIdentity->ProductName);
254         activeSources = newSource;
255         DSM_twCC = TWCC_SUCCESS;
256         return TWRC_SUCCESS;
257 }
258
259 /* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
260 TW_UINT16 TWAIN_UserSelect (pTW_IDENTITY pOrigin, TW_MEMREF pData)
261 {
262         pTW_IDENTITY    selected = (pTW_IDENTITY)pData;
263
264         if (!nrdevices) {
265                 DSM_twCC = TWCC_OPERATIONERROR;
266                 return TWRC_FAILURE;
267         }
268         *selected = devices[0].identity;
269         DSM_twCC = TWCC_SUCCESS;
270         return TWRC_SUCCESS;
271 }
272
273 /* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
274 TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
275 {
276     activeDS *currentDS = activeSources, *nextDS;
277
278     TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");
279
280     if (DSM_currentState == 3)
281     {
282         DSM_initialized = FALSE;
283         DSM_currentState = 2;
284
285         /* If there are data sources still open, close them now. */
286         while (currentDS != NULL)
287         {
288             nextDS = currentDS->next;
289             currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
290             HeapFree (GetProcessHeap(), 0, currentDS);
291             currentDS = nextDS;
292         }
293         activeSources = NULL;
294         DSM_twCC = TWCC_SUCCESS;
295         return TWRC_SUCCESS;
296     } else {
297         DSM_twCC = TWCC_SEQERROR;
298         return TWRC_FAILURE;
299     }
300 }
301
302 /* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
303 TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
304 {
305         TW_UINT16 twRC = TWRC_SUCCESS;
306
307         TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
308         if (DSM_currentState == 2) {
309                 if (!DSM_initialized) {
310                         DSM_currentDevice = 0;
311                         DSM_initialized = TRUE;
312                 }
313                 DSM_currentState = 3;
314                 DSM_twCC = TWCC_SUCCESS;
315                 twRC = TWRC_SUCCESS;
316         } else {
317                 /* operation invoked in invalid state */
318                 DSM_twCC = TWCC_SEQERROR;
319                 twRC = TWRC_FAILURE;
320         }
321         return twRC;
322 }
323
324 /* DG_CONTROL/DAT_STATUS/MSG_GET */
325 TW_UINT16 TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin, TW_MEMREF pData)
326 {
327         pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
328
329         TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
330
331         pSourceStatus->ConditionCode = DSM_twCC;
332         DSM_twCC = TWCC_SUCCESS;  /* clear the condition code */
333         return TWRC_SUCCESS;
334 }