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 BOOL detectionrun
= FALSE
;
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_initialized
) {
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");
286 DSM_initialized
= FALSE
;
288 /* If there are data sources still open, close them now. */
289 while (currentDS
!= NULL
)
291 nextDS
= currentDS
->next
;
292 currentDS
->dsEntry (pOrigin
, DG_CONTROL
, DAT_IDENTITY
, MSG_CLOSEDS
, pData
);
293 HeapFree (GetProcessHeap(), 0, currentDS
);
296 activeSources
= NULL
;
297 DSM_twCC
= TWCC_SUCCESS
;
300 DSM_twCC
= TWCC_SEQERROR
;
305 /* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
306 TW_UINT16
TWAIN_OpenDSM (pTW_IDENTITY pOrigin
, TW_MEMREF pData
)
308 TW_UINT16 twRC
= TWRC_SUCCESS
;
310 TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
311 if (!DSM_initialized
) {
312 DSM_currentDevice
= 0;
313 DSM_initialized
= TRUE
;
314 DSM_twCC
= TWCC_SUCCESS
;
317 /* operation invoked in invalid state */
318 DSM_twCC
= TWCC_SEQERROR
;
324 /* DG_CONTROL/DAT_STATUS/MSG_GET */
325 TW_UINT16
TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin
, TW_MEMREF pData
)
327 pTW_STATUS pSourceStatus
= (pTW_STATUS
) pData
;
329 TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
331 pSourceStatus
->ConditionCode
= DSM_twCC
;
332 DSM_twCC
= TWCC_SUCCESS
; /* clear the condition code */