ucrtbase: Add support for natural string widths.
[wine.git] / dlls / twain_32 / dsm_ctrl.c
blobb71c112967086767fafa3d856505e4919f3e1bcb
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 #include "windef.h"
29 #include "winbase.h"
30 #include "twain.h"
31 #include "twain_i.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(twain);
36 static TW_UINT16 DSM_initialized; /* whether Source Manager is initialized */
37 static TW_UINT32 DSM_sourceId; /* source id generator */
38 static TW_UINT16 DSM_currentDevice; /* keep track of device during enumeration */
40 struct all_devices {
41 char *modname;
42 TW_IDENTITY identity;
45 static int nrdevices = 0;
46 static struct all_devices *devices = NULL;
48 static void
49 twain_add_onedriver(const char *dsname) {
50 HMODULE hmod;
51 DSENTRYPROC dsEntry;
52 TW_IDENTITY fakeOrigin;
53 TW_IDENTITY sourceId;
54 TW_UINT16 ret;
56 hmod = LoadLibraryA(dsname);
57 if (!hmod) {
58 ERR("Failed to load TWAIN Source %s\n", dsname);
59 return;
61 dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry");
62 if (!dsEntry) {
63 ERR("Failed to find DS_Entry() in TWAIN DS %s\n", dsname);
64 return;
66 /* Loop to do multiple detects, mostly for sane.ds and gphoto2.ds */
67 do {
68 int i;
70 sourceId.Id = DSM_sourceId;
71 sourceId.ProtocolMajor = TWON_PROTOCOLMAJOR;
72 sourceId.ProtocolMinor = TWON_PROTOCOLMINOR;
73 ret = dsEntry (&fakeOrigin, DG_CONTROL, DAT_IDENTITY, MSG_GET, &sourceId);
74 if (ret != TWRC_SUCCESS) {
75 ERR("Source->(DG_CONTROL,DAT_IDENTITY,MSG_GET) failed!\n");
76 break;
78 TRACE("Manufacturer: %s\n", debugstr_a(sourceId.Manufacturer));
79 TRACE("ProductFamily: %s\n", debugstr_a(sourceId.ProductFamily));
80 TRACE("ProductName: %s\n", debugstr_a(sourceId.ProductName));
82 for (i=0;i<nrdevices;i++) {
83 if (!strcmp(sourceId.ProductName,devices[i].identity.ProductName))
84 break;
86 if (i < nrdevices)
87 break;
88 if (nrdevices)
89 devices = HeapReAlloc(GetProcessHeap(), 0, devices, sizeof(devices[0])*(nrdevices+1));
90 else
91 devices = HeapAlloc(GetProcessHeap(), 0, sizeof(devices[0]));
92 if ((devices[nrdevices].modname = HeapAlloc(GetProcessHeap(), 0, strlen(dsname) + 1)))
93 lstrcpyA(devices[nrdevices].modname, dsname);
94 devices[nrdevices].identity = sourceId;
95 nrdevices++;
96 DSM_sourceId++;
97 } while (1);
98 FreeLibrary (hmod);
101 static BOOL detectionrun = FALSE;
103 static void
104 twain_autodetect(void) {
105 if (detectionrun) return;
106 detectionrun = TRUE;
108 twain_add_onedriver("sane.ds");
109 twain_add_onedriver("gphoto2.ds");
110 #if 0
111 twain_add_onedriver("c:\\windows\\Twain_32\\Largan\\sp503a.ds");
112 twain_add_onedriver("c:\\windows\\Twain_32\\vivicam10\\vivicam10.ds");
113 twain_add_onedriver("c:\\windows\\Twain_32\\ws30slim\\sp500a.ds");
114 #endif
117 /* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
118 TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
120 TW_UINT16 twRC = TWRC_SUCCESS;
121 pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
122 activeDS *currentDS = NULL, *prevDS = NULL;
124 TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
126 for (currentDS = activeSources; currentDS; currentDS = currentDS->next) {
127 if (currentDS->identity.Id == pIdentity->Id)
128 break;
129 prevDS = currentDS;
131 if (!currentDS) {
132 DSM_twCC = TWCC_NODS;
133 return TWRC_FAILURE;
135 twRC = currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
136 /* This causes crashes due to still open Windows, so leave out for now.
137 * FreeLibrary (currentDS->hmod);
139 if (prevDS)
140 prevDS->next = currentDS->next;
141 else
142 activeSources = currentDS->next;
143 HeapFree (GetProcessHeap(), 0, currentDS);
144 if (twRC == TWRC_SUCCESS)
145 DSM_twCC = TWCC_SUCCESS;
146 else /* FIXME: unclear how to get TWCC */
147 DSM_twCC = TWCC_SEQERROR;
148 return twRC;
151 /* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
152 TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
154 pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
156 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
157 DSM_twCC = TWCC_NODS;
158 twain_autodetect();
159 if (!nrdevices)
160 return TWRC_FAILURE;
161 *pSourceIdentity = devices[0].identity;
162 DSM_twCC = TWCC_SUCCESS;
163 return TWRC_SUCCESS;
166 /* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
167 TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
169 pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
171 TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
172 twain_autodetect();
173 if (!nrdevices) {
174 TRACE ("no entries found.\n");
175 DSM_twCC = TWCC_NODS;
176 return TWRC_FAILURE;
178 DSM_currentDevice = 0;
179 *pSourceIdentity = devices[DSM_currentDevice++].identity;
180 return TWRC_SUCCESS;
183 /* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
184 TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
186 pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
188 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
189 if (!nrdevices || (DSM_currentDevice == nrdevices)) {
190 DSM_twCC = TWCC_SUCCESS;
191 return TWRC_ENDOFLIST;
193 *pSourceIdentity = devices[DSM_currentDevice++].identity;
194 return TWRC_SUCCESS;
197 /* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
198 TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
200 TW_UINT16 i = 0;
201 pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
202 activeDS *newSource;
203 const char *modname = NULL;
204 HMODULE hmod;
206 TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
207 TRACE("pIdentity is %s\n", pIdentity->ProductName);
208 if (!DSM_initialized) {
209 FIXME("seq error\n");
210 DSM_twCC = TWCC_SEQERROR;
211 return TWRC_FAILURE;
213 twain_autodetect();
214 if (!nrdevices) {
215 FIXME("no devs.\n");
216 DSM_twCC = TWCC_NODS;
217 return TWRC_FAILURE;
220 if (pIdentity->ProductName[0] != '\0') {
221 /* Make sure the source to be opened exists in the device list */
222 for (i = 0; i<nrdevices; i++)
223 if (!strcmp (devices[i].identity.ProductName, pIdentity->ProductName))
224 break;
225 if (i == nrdevices)
226 i = 0;
227 } /* else use the first device */
229 /* the source is found in the device list */
230 newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
231 if (!newSource) {
232 DSM_twCC = TWCC_LOWMEMORY;
233 FIXME("Out of memory.\n");
234 return TWRC_FAILURE;
236 hmod = LoadLibraryA(devices[i].modname);
237 if (!hmod) {
238 ERR("Failed to load TWAIN Source %s\n", modname);
239 DSM_twCC = TWCC_OPERATIONERROR;
240 HeapFree(GetProcessHeap(), 0, newSource);
241 return TWRC_FAILURE;
243 newSource->hmod = hmod;
244 newSource->dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry");
245 if (TWRC_SUCCESS != newSource->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, pIdentity)) {
246 DSM_twCC = TWCC_OPERATIONERROR;
247 HeapFree(GetProcessHeap(), 0, newSource);
248 return TWRC_FAILURE;
250 /* Assign name and id for the opened data source */
251 pIdentity->Id = DSM_sourceId ++;
252 /* add the data source to an internal active source list */
253 newSource->next = activeSources;
254 newSource->identity.Id = pIdentity->Id;
255 strcpy (newSource->identity.ProductName, pIdentity->ProductName);
256 activeSources = newSource;
257 DSM_twCC = TWCC_SUCCESS;
258 return TWRC_SUCCESS;
261 /* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
262 TW_UINT16 TWAIN_UserSelect (pTW_IDENTITY pOrigin, TW_MEMREF pData)
264 pTW_IDENTITY selected = (pTW_IDENTITY)pData;
266 if (!nrdevices) {
267 DSM_twCC = TWCC_OPERATIONERROR;
268 return TWRC_FAILURE;
270 *selected = devices[0].identity;
271 DSM_twCC = TWCC_SUCCESS;
272 return TWRC_SUCCESS;
275 /* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
276 TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
278 activeDS *currentDS = activeSources, *nextDS;
280 TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");
282 if (DSM_initialized)
284 DSM_initialized = FALSE;
286 /* If there are data sources still open, close them now. */
287 while (currentDS != NULL)
289 nextDS = currentDS->next;
290 currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
291 HeapFree (GetProcessHeap(), 0, currentDS);
292 currentDS = nextDS;
294 activeSources = NULL;
295 DSM_twCC = TWCC_SUCCESS;
296 return TWRC_SUCCESS;
297 } else {
298 DSM_twCC = TWCC_SEQERROR;
299 return TWRC_FAILURE;
303 /* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
304 TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
306 TW_UINT16 twRC = TWRC_SUCCESS;
308 TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
309 if (!DSM_initialized) {
310 DSM_currentDevice = 0;
311 DSM_initialized = TRUE;
312 DSM_twCC = TWCC_SUCCESS;
313 twRC = TWRC_SUCCESS;
314 } else {
315 /* operation invoked in invalid state */
316 DSM_twCC = TWCC_SEQERROR;
317 twRC = TWRC_FAILURE;
319 return twRC;
322 /* DG_CONTROL/DAT_STATUS/MSG_GET */
323 TW_UINT16 TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin, TW_MEMREF pData)
325 pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
327 TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
329 pSourceStatus->ConditionCode = DSM_twCC;
330 DSM_twCC = TWCC_SUCCESS; /* clear the condition code */
331 return TWRC_SUCCESS;