2 * TWAIN32 Source Manager
4 * Copyright 2000 Corel Corporation
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.
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.
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
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(twain
);
37 /* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
38 TW_UINT16
TWAIN_CloseDS (pTW_IDENTITY pOrigin
, TW_MEMREF pData
)
44 TW_UINT16 twRC
= TWRC_SUCCESS
;
45 pTW_IDENTITY pIdentity
= (pTW_IDENTITY
) pData
;
46 activeDS
*currentDS
= NULL
, *prevDS
= NULL
;
48 TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
50 for (currentDS
= activeSources
; currentDS
; currentDS
= currentDS
->next
)
52 if (currentDS
->identity
.Id
== pIdentity
->Id
)
58 /* Only valid to close a data source if it is in state 4 */
59 if (currentDS
->currentState
== 4)
61 sane_close (currentDS
->deviceHandle
);
62 /* remove the data source from active data source list */
64 prevDS
->next
= currentDS
->next
;
66 activeSources
= currentDS
->next
;
67 HeapFree (GetProcessHeap(), 0, currentDS
);
69 DSM_twCC
= TWCC_SUCCESS
;
74 DSM_twCC
= TWCC_SEQERROR
;
87 /* Sane returns device names that are longer than the 32 bytes allowed
88 by TWAIN. However, it colon separates them, and the last bit is
89 the most interesting. So we use the last bit, and add a signature
90 to ensure uniqueness */
92 static void copy_sane_short_name(const char *in
, char *out
, size_t outsize
)
97 if (strlen(in
) <= outsize
- 1)
103 for (p
= in
; *p
; p
++)
106 p
= strrchr(in
, ':');
112 if (strlen(p
) > outsize
- 7 - 1)
113 p
+= strlen(p
) - (outsize
- 7 - 1);
116 sprintf(out
+ strlen(out
), "(%04X)", signature
% 0x10000);
121 /* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
122 TW_UINT16
TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin
, TW_MEMREF pData
)
125 DSM_twCC
= TWCC_NODS
;
128 TW_UINT16 twRC
= TWRC_SUCCESS
;
129 pTW_IDENTITY pSourceIdentity
= (pTW_IDENTITY
) pData
;
131 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
135 if ((sane_get_devices (&device_list
, SANE_FALSE
) != SANE_STATUS_GOOD
))
137 DSM_twCC
= TWCC_NODS
;
142 /* FIXME: the default device is not necessarily the first device. *
143 * Users should be able to choose the default device */
144 if (device_list
&& device_list
[0])
146 pSourceIdentity
->Id
= DSM_sourceId
++;
147 copy_sane_short_name(device_list
[0]->name
, pSourceIdentity
->ProductName
, sizeof(pSourceIdentity
->ProductName
) - 1);
148 TRACE("got: %s (short [%s]), %s, %s\n", device_list
[0]->name
, pSourceIdentity
->ProductName
, device_list
[0]->vendor
, device_list
[0]->model
);
149 lstrcpynA (pSourceIdentity
->Manufacturer
, device_list
[0]->vendor
, sizeof(pSourceIdentity
->Manufacturer
) - 1);
150 lstrcpynA (pSourceIdentity
->ProductFamily
, device_list
[0]->model
, sizeof(pSourceIdentity
->ProductFamily
) - 1);
151 pSourceIdentity
->ProtocolMajor
= TWON_PROTOCOLMAJOR
;
152 pSourceIdentity
->ProtocolMinor
= TWON_PROTOCOLMINOR
;
155 DSM_twCC
= TWCC_SUCCESS
;
161 DSM_twCC
= TWCC_NODS
;
168 /* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
169 TW_UINT16
TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin
, TW_MEMREF pData
)
172 DSM_twCC
= TWCC_NODS
;
175 TW_UINT16 twRC
= TWRC_SUCCESS
;
176 pTW_IDENTITY pSourceIdentity
= (pTW_IDENTITY
) pData
;
179 TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
182 status
= sane_get_devices (&device_list
, SANE_FALSE
);
183 if (status
== SANE_STATUS_GOOD
)
187 pSourceIdentity
->Id
= DSM_sourceId
++;
188 copy_sane_short_name(device_list
[0]->name
, pSourceIdentity
->ProductName
, sizeof(pSourceIdentity
->ProductName
) - 1);
189 TRACE("got: %s (short [%s]), %s, %s\n", device_list
[0]->name
, pSourceIdentity
->ProductName
, device_list
[0]->vendor
, device_list
[0]->model
);
190 lstrcpynA (pSourceIdentity
->Manufacturer
, device_list
[0]->vendor
, sizeof(pSourceIdentity
->Manufacturer
) - 1);
191 lstrcpynA (pSourceIdentity
->ProductFamily
, device_list
[0]->model
, sizeof(pSourceIdentity
->ProductFamily
) - 1);
192 pSourceIdentity
->ProtocolMajor
= TWON_PROTOCOLMAJOR
;
193 pSourceIdentity
->ProtocolMinor
= TWON_PROTOCOLMINOR
;
195 DSM_currentDevice
= 1;
197 DSM_twCC
= TWCC_SUCCESS
;
201 TRACE("got empty device list\n");
203 DSM_twCC
= TWCC_NODS
;
206 else if (status
== SANE_STATUS_NO_MEM
)
209 DSM_twCC
= TWCC_LOWMEMORY
;
213 WARN("sane_get_devices() failed: %s\n", sane_strstatus (status
));
215 DSM_twCC
= TWCC_NODS
;
222 /* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
223 TW_UINT16
TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin
, TW_MEMREF pData
)
226 DSM_twCC
= TWCC_SUCCESS
;
227 return TWRC_ENDOFLIST
;
229 TW_UINT16 twRC
= TWRC_SUCCESS
;
230 pTW_IDENTITY pSourceIdentity
= (pTW_IDENTITY
) pData
;
232 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
234 if (device_list
&& device_list
[DSM_currentDevice
] &&
235 device_list
[DSM_currentDevice
]->name
&&
236 device_list
[DSM_currentDevice
]->vendor
&&
237 device_list
[DSM_currentDevice
]->model
)
239 pSourceIdentity
->Id
= DSM_sourceId
++;
240 copy_sane_short_name(device_list
[DSM_currentDevice
]->name
, pSourceIdentity
->ProductName
, sizeof(pSourceIdentity
->ProductName
) - 1);
241 TRACE("got: %s (short [%s]), %s, %s\n", device_list
[DSM_currentDevice
]->name
, pSourceIdentity
->ProductName
, device_list
[DSM_currentDevice
]->vendor
, device_list
[DSM_currentDevice
]->model
);
242 lstrcpynA (pSourceIdentity
->Manufacturer
, device_list
[DSM_currentDevice
]->vendor
, sizeof(pSourceIdentity
->Manufacturer
) - 1);
243 lstrcpynA (pSourceIdentity
->ProductFamily
, device_list
[DSM_currentDevice
]->model
, sizeof(pSourceIdentity
->ProductFamily
) - 1);
244 pSourceIdentity
->ProtocolMajor
= TWON_PROTOCOLMAJOR
;
245 pSourceIdentity
->ProtocolMinor
= TWON_PROTOCOLMINOR
;
246 DSM_currentDevice
++;
249 DSM_twCC
= TWCC_SUCCESS
;
253 DSM_twCC
= TWCC_SUCCESS
;
254 twRC
= TWRC_ENDOFLIST
;
261 /* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
262 TW_UINT16
TWAIN_OpenDS (pTW_IDENTITY pOrigin
, TW_MEMREF pData
)
265 DSM_twCC
= TWCC_NODS
;
268 TW_UINT16 twRC
= TWRC_SUCCESS
, i
= 0;
269 pTW_IDENTITY pIdentity
= (pTW_IDENTITY
) pData
;
274 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
276 if (DSM_currentState
!= 3)
278 DSM_twCC
= TWCC_SEQERROR
;
283 (sane_get_devices (&device_list
, SANE_FALSE
) != SANE_STATUS_GOOD
))
285 DSM_twCC
= TWCC_NODS
;
289 if (pIdentity
->ProductName
[0] != '\0')
291 /* Make sure the source to be opened exists in the device list */
292 for (i
= 0; device_list
[i
]; i
++)
294 copy_sane_short_name(device_list
[i
]->name
, shortname
, sizeof(shortname
) - 1);
295 if (strcmp (shortname
, pIdentity
->ProductName
) == 0)
303 /* the source is found in the device list */
304 newSource
= HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS
));
307 newSource
->deviceIndex
= i
;
308 status
= sane_open(device_list
[i
]->name
,&newSource
->deviceHandle
);
309 if (status
== SANE_STATUS_GOOD
)
311 /* Assign name and id for the opened data source */
312 lstrcpynA (pIdentity
->ProductName
, shortname
, sizeof(pIdentity
->ProductName
) - 1);
313 pIdentity
->Id
= DSM_sourceId
++;
314 /* add the data source to an internal active source list */
315 newSource
->next
= activeSources
;
316 newSource
->identity
.Id
= pIdentity
->Id
;
317 strcpy (newSource
->identity
.ProductName
, pIdentity
->ProductName
);
318 newSource
->currentState
= 4; /*transition into state 4*/
319 newSource
->twCC
= TWCC_SUCCESS
;
320 activeSources
= newSource
;
322 DSM_twCC
= TWCC_SUCCESS
;
327 DSM_twCC
= TWCC_OPERATIONERROR
;
333 DSM_twCC
= TWCC_LOWMEMORY
;
339 DSM_twCC
= TWCC_NODS
;
346 /* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
347 TW_UINT16
TWAIN_UserSelect (pTW_IDENTITY pOrigin
, TW_MEMREF pData
)
352 TW_UINT16 twRC
= TWRC_SUCCESS
;
354 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT\n");
356 /* FIXME: we should replace xscanimage with our own User Select UI */
357 system("xscanimage");
359 DSM_twCC
= TWCC_SUCCESS
;
364 /* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
365 TW_UINT16
TWAIN_CloseDSM (pTW_IDENTITY pOrigin
, TW_MEMREF pData
)
370 TW_UINT16 twRC
= TWRC_SUCCESS
;
371 activeDS
*currentDS
= activeSources
, *nextDS
;
373 TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");
375 if (DSM_currentState
== 3)
378 DSM_initialized
= FALSE
;
380 DSM_currentState
= 2;
382 /* If there are data sources still open, close them now. */
383 while (currentDS
!= NULL
)
385 nextDS
= currentDS
->next
;
386 sane_close (currentDS
->deviceHandle
);
387 HeapFree (GetProcessHeap(), 0, currentDS
);
390 activeSources
= NULL
;
391 DSM_twCC
= TWCC_SUCCESS
;
396 DSM_twCC
= TWCC_SEQERROR
;
404 /* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
405 TW_UINT16
TWAIN_OpenDSM (pTW_IDENTITY pOrigin
, TW_MEMREF pData
)
410 TW_UINT16 twRC
= TWRC_SUCCESS
;
412 SANE_Int version_code
;
414 TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
416 if (DSM_currentState
== 2)
418 if (!DSM_initialized
)
420 DSM_initialized
= TRUE
;
421 status
= sane_init (&version_code
, NULL
);
423 DSM_currentDevice
= 0;
426 DSM_parentHWND
= *(TW_HANDLE
*)pData
;
427 DSM_currentState
= 3; /* transition to state 3 */
428 DSM_twCC
= TWCC_SUCCESS
;
433 /* operation invoked in invalid state */
434 DSM_twCC
= TWCC_SEQERROR
;
442 /* DG_CONTROL/DAT_STATUS/MSG_GET */
443 TW_UINT16
TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin
, TW_MEMREF pData
)
445 pTW_STATUS pSourceStatus
= (pTW_STATUS
) pData
;
447 TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
449 pSourceStatus
->ConditionCode
= DSM_twCC
;
450 DSM_twCC
= TWCC_SUCCESS
; /* clear the condition code */