readme.de: Git is not an acronym.
[wine/hramrach.git] / dlls / twain_32 / dsm_ctrl.c
blobc34bd1d987dacfe2897e1cf5abc0c9e39abb2016
1 /*
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
22 #include "config.h"
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
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"
36 WINE_DEFAULT_DEBUG_CHANNEL(twain);
38 struct all_devices {
39 char *modname;
40 TW_IDENTITY identity;
43 static int nrdevices = 0;
44 static struct all_devices *devices = NULL;
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;
54 hmod = LoadLibraryA(dsname);
55 if (!hmod) {
56 ERR("Failed to load TWAIN Source %s\n", dsname);
57 return;
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;
64 /* Loop to do multiple detects, mostly for sane.ds and gphoto2.ds */
65 do {
66 int i;
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;
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));
80 for (i=0;i<nrdevices;i++) {
81 if (!strcmp(sourceId.ProductName,devices[i].identity.ProductName))
82 break;
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);
99 static int detectionrun = 0;
101 static void
102 twain_autodetect(void) {
103 if (detectionrun) return;
104 detectionrun = 1;
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
115 /* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
116 TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
118 TW_UINT16 twRC = TWRC_SUCCESS;
119 pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
120 activeDS *currentDS = NULL, *prevDS = NULL;
122 TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
124 for (currentDS = activeSources; currentDS; currentDS = currentDS->next) {
125 if (currentDS->identity.Id == pIdentity->Id)
126 break;
127 prevDS = currentDS;
129 if (!currentDS) {
130 DSM_twCC = TWCC_NODS;
131 return TWRC_FAILURE;
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);
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;
149 /* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
150 TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
152 pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
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;
164 /* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
165 TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
167 pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
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;
176 DSM_currentDevice = 0;
177 *pSourceIdentity = devices[DSM_currentDevice++].identity;
178 return TWRC_SUCCESS;
181 /* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
182 TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
184 pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
186 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
187 if (!nrdevices || (DSM_currentDevice == nrdevices)) {
188 DSM_twCC = TWCC_SUCCESS;
189 return TWRC_ENDOFLIST;
191 *pSourceIdentity = devices[DSM_currentDevice++].identity;
192 return TWRC_SUCCESS;
195 /* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
196 TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
198 TW_UINT16 i = 0;
199 pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
200 activeDS *newSource;
201 const char *modname = NULL;
202 HMODULE hmod;
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;
211 twain_autodetect();
212 if (!nrdevices) {
213 FIXME("no devs.\n");
214 DSM_twCC = TWCC_NODS;
215 return TWRC_FAILURE;
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 */
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;
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;
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;
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;
259 /* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
260 TW_UINT16 TWAIN_UserSelect (pTW_IDENTITY pOrigin, TW_MEMREF pData)
262 pTW_IDENTITY selected = (pTW_IDENTITY)pData;
264 if (!nrdevices) {
265 DSM_twCC = TWCC_OPERATIONERROR;
266 return TWRC_FAILURE;
268 *selected = devices[0].identity;
269 DSM_twCC = TWCC_SUCCESS;
270 return TWRC_SUCCESS;
273 /* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
274 TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
276 activeDS *currentDS = activeSources, *nextDS;
278 TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");
280 if (DSM_currentState == 3)
282 DSM_initialized = FALSE;
283 DSM_currentState = 2;
285 /* If there are data sources still open, close them now. */
286 while (currentDS != NULL)
288 nextDS = currentDS->next;
289 currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
290 HeapFree (GetProcessHeap(), 0, currentDS);
291 currentDS = nextDS;
293 activeSources = NULL;
294 DSM_twCC = TWCC_SUCCESS;
295 return TWRC_SUCCESS;
296 } else {
297 DSM_twCC = TWCC_SEQERROR;
298 return TWRC_FAILURE;
302 /* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
303 TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
305 TW_UINT16 twRC = TWRC_SUCCESS;
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;
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;
321 return twRC;
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 */
333 return TWRC_SUCCESS;