kernel32: FindFirstChangeNotification needs a static IO_STATUS_BLOCK.
[wine] / dlls / twain / dsm_ctrl.c
1 /*
2  * TWAIN32 Source Manager
3  *
4  * Copyright 2000 Corel Corporation
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "windef.h"
29 #include "winbase.h"
30 #include "twain.h"
31 #include "twain_i.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(twain);
35
36 /* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
37 TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
38 {
39 #ifndef HAVE_SANE
40     DSM_twCC = TWCC_NODS;
41     return TWRC_FAILURE;
42 #else
43     TW_UINT16 twRC = TWRC_SUCCESS;
44     pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
45     activeDS *currentDS = NULL, *prevDS = NULL;
46
47     TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
48
49     for (currentDS = activeSources; currentDS; currentDS = currentDS->next)
50     {
51         if (currentDS->identity.Id == pIdentity->Id)
52             break;
53         prevDS = currentDS;
54     }
55     if (currentDS)
56     {
57         /* Only valid to close a data source if it is in state 4 */
58         if (currentDS->currentState == 4)
59         {
60             sane_close (currentDS->deviceHandle);
61             /* remove the data source from active data source list */
62             if (prevDS)
63                 prevDS->next = currentDS->next;
64             else
65                 activeSources = currentDS->next;
66             HeapFree (GetProcessHeap(), 0, currentDS);
67             twRC = TWRC_SUCCESS;
68             DSM_twCC = TWCC_SUCCESS;
69         }
70         else
71         {
72             twRC = TWRC_FAILURE;
73             DSM_twCC = TWCC_SEQERROR;
74         }
75     }
76     else
77     {
78         twRC = TWRC_FAILURE;
79         DSM_twCC = TWCC_NODS;
80     }
81
82     return twRC;
83 #endif
84 }
85
86 /* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
87 TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
88 {
89 #ifndef HAVE_SANE
90     DSM_twCC = TWCC_NODS;
91     return TWRC_FAILURE;
92 #else
93     TW_UINT16 twRC = TWRC_SUCCESS;
94     pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
95
96     TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
97
98     if (!device_list)
99     {
100         if ((sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
101         {
102             DSM_twCC = TWCC_NODS;
103             return TWRC_FAILURE;
104         }
105     }
106
107     /* FIXME: the default device is not necessarily the first device.  *
108      * Users should be able to choose the default device               */
109     if (device_list && device_list[0])
110     {
111         pSourceIdentity->Id = DSM_sourceId ++;
112         strcpy (pSourceIdentity->ProductName, device_list[0]->name);
113         strcpy (pSourceIdentity->Manufacturer, device_list[0]->vendor);
114         strcpy (pSourceIdentity->ProductFamily, device_list[0]->model);
115         pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
116         pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
117
118         twRC = TWRC_SUCCESS;
119         DSM_twCC = TWCC_SUCCESS;
120     }
121     else
122     {
123         twRC = TWRC_FAILURE;
124         DSM_twCC = TWCC_NODS;
125     }
126
127     return twRC;
128 #endif
129 }
130
131 /* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
132 TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
133 {
134 #ifndef HAVE_SANE
135     DSM_twCC = TWCC_NODS;
136     return TWRC_FAILURE;
137 #else
138     TW_UINT16 twRC = TWRC_SUCCESS;
139     pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
140     SANE_Status status;
141
142     TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
143
144     status = sane_get_devices (&device_list, SANE_FALSE);
145     if (status == SANE_STATUS_GOOD)
146     {
147         if (device_list[0])
148         {
149             TRACE("got: %s, %s, %s\n", device_list[0]->name, device_list[0]->vendor, device_list[0]->model);
150             pSourceIdentity->Id = DSM_sourceId ++;
151             strcpy (pSourceIdentity->ProductName, device_list[0]->name);
152             strcpy (pSourceIdentity->Manufacturer, device_list[0]->vendor);
153             strcpy (pSourceIdentity->ProductFamily, device_list[0]->model);
154             pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
155             pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
156
157             DSM_currentDevice = 1;
158             twRC = TWRC_SUCCESS;
159             DSM_twCC = TWCC_SUCCESS;
160         }
161         else
162         {
163             TRACE("got empty device list\n");
164             twRC = TWRC_FAILURE;
165             DSM_twCC = TWCC_NODS;
166         }
167     }
168     else if (status == SANE_STATUS_NO_MEM)
169     {
170         twRC = TWRC_FAILURE;
171         DSM_twCC = TWCC_LOWMEMORY;
172     }
173     else
174     {
175         WARN("sane_get_devices() failed: %s\n", sane_strstatus (status));
176         twRC = TWRC_FAILURE;
177         DSM_twCC = TWCC_NODS;
178     }
179
180     return twRC;
181 #endif
182 }
183
184 /* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
185 TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
186 {
187 #ifndef HAVE_SANE
188     DSM_twCC = TWCC_SUCCESS;
189     return TWRC_ENDOFLIST;
190 #else
191     TW_UINT16 twRC = TWRC_SUCCESS;
192     pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
193
194     TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
195
196     if (device_list && device_list[DSM_currentDevice] &&
197         device_list[DSM_currentDevice]->name &&
198         device_list[DSM_currentDevice]->vendor &&
199         device_list[DSM_currentDevice]->model)
200     {
201         pSourceIdentity->Id = DSM_sourceId ++;
202         strcpy (pSourceIdentity->ProductName, device_list[DSM_currentDevice]->name);
203         strcpy (pSourceIdentity->Manufacturer, device_list[DSM_currentDevice]->vendor);
204         strcpy (pSourceIdentity->ProductFamily, device_list[DSM_currentDevice]->model);
205         pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
206         pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
207         DSM_currentDevice ++;
208
209         twRC = TWRC_SUCCESS;
210         DSM_twCC = TWCC_SUCCESS;
211     }
212     else
213     {
214         DSM_twCC = TWCC_SUCCESS;
215         twRC = TWRC_ENDOFLIST;
216     }
217
218     return twRC;
219 #endif
220 }
221
222 /* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
223 TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
224 {
225 #ifndef HAVE_SANE
226     DSM_twCC = TWCC_NODS;
227     return TWRC_FAILURE;
228 #else
229     TW_UINT16 twRC = TWRC_SUCCESS, i = 0;
230     pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
231     activeDS *newSource;
232     SANE_Status status;
233
234     TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
235
236     if (DSM_currentState != 3)
237     {
238         DSM_twCC = TWCC_SEQERROR;
239         return TWRC_FAILURE;
240     }
241
242     if (!device_list &&
243        (sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
244     {
245         DSM_twCC = TWCC_NODS;
246         return TWRC_FAILURE;
247     }
248
249     if (pIdentity->ProductName[0] != '\0')
250     {
251         /* Make sure the source to be opened exists in the device list */
252         for (i = 0; device_list[i]; i ++)
253         {
254             if (strcmp (device_list[i]->name, pIdentity->ProductName) == 0)
255                 break;
256         }
257     }
258
259     if (device_list[i])
260     {
261         /* the source is found in the device list */
262         newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
263         if (newSource)
264         {
265             status = sane_open(device_list[i]->name,&newSource->deviceHandle);
266             if (status == SANE_STATUS_GOOD)
267             {
268                 /* Assign name and id for the opened data source */
269                 strcpy (pIdentity->ProductName, device_list[i]->name);
270                 pIdentity->Id = DSM_sourceId ++;
271                 /* add the data source to an internal active source list */
272                 newSource->next = activeSources;
273                 newSource->identity.Id = pIdentity->Id;
274                 strcpy (newSource->identity.ProductName, pIdentity->ProductName);
275                 newSource->currentState = 4; /*transition into state 4*/
276                 newSource->twCC = TWCC_SUCCESS;
277                 activeSources = newSource;
278                 twRC = TWRC_SUCCESS;
279                 DSM_twCC = TWCC_SUCCESS;
280             }
281             else
282             {
283                 twRC = TWRC_FAILURE;
284                 DSM_twCC = TWCC_OPERATIONERROR;
285             }
286         }
287         else
288         {
289             twRC = TWRC_FAILURE;
290             DSM_twCC = TWCC_LOWMEMORY;
291         }
292     }
293     else
294     {
295         twRC = TWRC_FAILURE;
296         DSM_twCC = TWCC_NODS;
297     }
298
299     return twRC;
300 #endif
301 }
302
303 /* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
304 TW_UINT16 TWAIN_UserSelect (pTW_IDENTITY pOrigin, TW_MEMREF pData)
305 {
306 #ifndef HAVE_SANE
307     return TWRC_SUCCESS;
308 #else
309     TW_UINT16 twRC = TWRC_SUCCESS;
310
311     TRACE("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT\n");
312
313     /* FIXME: we should replace xscanimage with our own  User Select UI */
314     system("xscanimage");
315
316     DSM_twCC = TWCC_SUCCESS;
317     return twRC;
318 #endif
319 }
320
321 /* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
322 TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
323 {
324 #ifndef HAVE_SANE
325     return TWRC_FAILURE;
326 #else
327     TW_UINT16 twRC = TWRC_SUCCESS;
328     activeDS *currentDS = activeSources, *nextDS;
329
330     TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");
331
332     if (DSM_currentState == 3)
333     {
334         sane_exit ();
335         DSM_initialized = FALSE;
336         DSM_parentHWND = 0;
337         DSM_currentState = 2;
338
339         /* If there are data sources still open, close them now. */
340         while (currentDS != NULL)
341         {
342             nextDS = currentDS->next;
343             sane_close (currentDS->deviceHandle);
344             HeapFree (GetProcessHeap(), 0, currentDS);
345             currentDS = nextDS;
346         }
347         activeSources = NULL;
348         DSM_twCC = TWCC_SUCCESS;
349         twRC = TWRC_SUCCESS;
350     }
351     else
352     {
353         DSM_twCC = TWCC_SEQERROR;
354         twRC = TWRC_FAILURE;
355     }
356
357     return twRC;
358 #endif
359 }
360
361 /* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
362 TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
363 {
364 #ifndef HAVE_SANE
365     return TWRC_FAILURE;
366 #else
367     TW_UINT16 twRC = TWRC_SUCCESS;
368     SANE_Status status;
369     SANE_Int version_code;
370
371     TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
372
373     if (DSM_currentState == 2)
374     {
375         if (!DSM_initialized)
376         {
377             DSM_initialized = TRUE;
378             status = sane_init (&version_code, NULL);
379             device_list = NULL;
380             DSM_currentDevice = 0;
381             DSM_sourceId = 0;
382         }
383         DSM_parentHWND = *(TW_HANDLE*)pData;
384         DSM_currentState = 3; /* transition to state 3 */
385         DSM_twCC = TWCC_SUCCESS;
386         twRC = TWRC_SUCCESS;
387     }
388     else
389     {
390         /* operation invoked in invalid state */
391         DSM_twCC = TWCC_SEQERROR;
392         twRC = TWRC_FAILURE;
393     }
394
395     return twRC;
396 #endif
397 }
398
399 /* DG_CONTROL/DAT_STATUS/MSG_GET */
400 TW_UINT16 TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin, TW_MEMREF pData)
401 {
402     pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
403
404     TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
405
406     pSourceStatus->ConditionCode = DSM_twCC;
407     DSM_twCC = TWCC_SUCCESS;  /* clear the condition code */
408
409     return TWRC_SUCCESS;
410 }