1 /*
2 * Implementation of the ODBC driver installer
3 *
4 * Copyright 2005 Mike McCormack for CodeWeavers
5 * Copyright 2005 Hans Leidekker
6 * Copyright 2007 Bill Medland
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include <assert.h>
24 #include <stdarg.h>
25
26 #define COBJMACROS
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "winnls.h"
32 #include "sqlext.h"
33 #ifdef __REACTOS__
34 #undef TRACE_ON
35 #endif
36 #include "wine/debug.h"
37 #include "wine/heap.h"
38
39 #include "odbcinst.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(odbc);
42
43 /* Registry key names */
44 static const WCHAR drivers_key[] = {'S','o','f','t','w','a','r','e','\\','O','D','B','C','\\','O','D','B','C','I','N','S','T','.','I','N','I','\\','O','D','B','C',' ','D','r','i','v','e','r','s',0};
45 static const WCHAR odbcW[] = {'S','o','f','t','w','a','r','e','\\','O','D','B','C',0};
46 static const WCHAR odbcini[] = {'S','o','f','t','w','a','r','e','\\','O','D','B','C','\\','O','D','B','C','I','N','S','T','.','I','N','I','\\',0};
47 static const WCHAR odbcdrivers[] = {'O','D','B','C',' ','D','r','i','v','e','r','s',0};
48 static const WCHAR odbctranslators[] = {'O','D','B','C',' ','T','r','a','n','s','l','a','t','o','r','s',0};
49
50 /* This config mode is known to be process-wide.
51 * MSDN documentation suggests that the value is hidden somewhere in the registry but I haven't found it yet.
52 * Although both the registry and the ODBC.ini files appear to be maintained together they are not maintained automatically through the registry's IniFileMapping.
53 */
54 static UWORD config_mode = ODBC_BOTH_DSN;
55
56 /* MSDN documentation suggests that the error subsystem handles errors 1 to 8
57 * only and experimentation (Windows 2000) shows that the errors are process-
58 * wide so go for the simple solution; static arrays.
59 */
60 static int num_errors;
61 static int error_code[8];
62 static const WCHAR *error_msg[8];
63 static const WCHAR odbc_error_general_err[] = {'G','e','n','e','r','a','l',' ','e','r','r','o','r',0};
64 static const WCHAR odbc_error_invalid_buff_len[] = {'I','n','v','a','l','i','d',' ','b','u','f','f','e','r',' ','l','e','n','g','t','h',0};
65 static const WCHAR odbc_error_component_not_found[] = {'C','o','m','p','o','n','e','n','t',' ','n','o','t',' ','f','o','u','n','d',0};
66 static const WCHAR odbc_error_out_of_mem[] = {'O','u','t',' ','o','f',' ','m','e','m','o','r','y',0};
67 static const WCHAR odbc_error_invalid_param_sequence[] = {'I','n','v','a','l','i','d',' ','p','a','r','a','m','e','t','e','r',' ','s','e','q','u','e','n','c','e',0};
68 static const WCHAR odbc_error_invalid_param_string[] = {'I','n','v','a','l','i','d',' ','p','a','r','a','m','e','t','e','r',' ','s','t','r','i','n','g',0};
69 static const WCHAR odbc_error_invalid_dsn[] = {'I','n','v','a','l','i','d',' ','D','S','N',0};
70 static const WCHAR odbc_error_load_lib_failed[] = {'L','o','a','d',' ','L','i','b','r','a','r','y',' ','F','a','i','l','e','d',0};
71 static const WCHAR odbc_error_request_failed[] = {'R','e','q','u','e','s','t',' ','F','a','i','l','e','d',0};
72 static const WCHAR odbc_error_invalid_keyword[] = {'I','n','v','a','l','i','d',' ','k','e','y','w','o','r','d',' ','v','a','l','u','e',0};
73
74 /* Push an error onto the error stack, taking care of ranges etc. */
push_error(int code,LPCWSTR msg)75 static void push_error(int code, LPCWSTR msg)
76 {
77 if (num_errors < ARRAY_SIZE(error_code))
78 {
79 error_code[num_errors] = code;
80 error_msg[num_errors] = msg;
81 num_errors++;
82 }
83 }
84
85 /* Clear the error stack */
clear_errors(void)86 static void clear_errors(void)
87 {
88 num_errors = 0;
89 }
90
heap_strdupAtoW(const char * str)91 static inline WCHAR *heap_strdupAtoW(const char *str)
92 {
93 LPWSTR ret = NULL;
94
95 if(str) {
96 DWORD len;
97
98 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
99 ret = heap_alloc(len*sizeof(WCHAR));
100 if(ret)
101 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
102 }
103
104 return ret;
105 }
106
107
ODBCCPlApplet(LONG i,LONG j,LONG * p1,LONG * p2)108 BOOL WINAPI ODBCCPlApplet( LONG i, LONG j, LONG * p1, LONG * p2)
109 {
110 clear_errors();
111 FIXME( "( %d %d %p %p) : stub!\n", i, j, p1, p2);
112 return FALSE;
113 }
114
SQLInstall_strdup_multi(LPCSTR str)115 static LPWSTR SQLInstall_strdup_multi(LPCSTR str)
116 {
117 LPCSTR p;
118 LPWSTR ret = NULL;
119 DWORD len;
120
121 if (!str)
122 return ret;
123
124 for (p = str; *p; p += lstrlenA(p) + 1)
125 ;
126
127 len = MultiByteToWideChar(CP_ACP, 0, str, p - str, NULL, 0 );
128 ret = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
129 MultiByteToWideChar(CP_ACP, 0, str, p - str, ret, len );
130 ret[len] = 0;
131
132 return ret;
133 }
134
SQLInstall_strdup(LPCSTR str)135 static LPWSTR SQLInstall_strdup(LPCSTR str)
136 {
137 DWORD len;
138 LPWSTR ret = NULL;
139
140 if (!str)
141 return ret;
142
143 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0 );
144 ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
145 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len );
146
147 return ret;
148 }
149
150 /* Convert the wide string or zero-length-terminated list of wide strings to a
151 * narrow string or zero-length-terminated list of narrow strings.
152 * Do not try to emulate windows undocumented excesses (e.g. adding a third \0
153 * to a list)
154 * Arguments
155 * mode Indicates the sort of string.
156 * 1 denotes that the buffers contain strings terminated by a single nul
157 * character
158 * 2 denotes that the buffers contain zero-length-terminated lists
159 * (frequently erroneously referred to as double-null-terminated)
160 * buffer The narrow-character buffer into which to place the result. This
161 * must be a non-null pointer to the first element of a buffer whose
162 * length is passed in buffer_length.
163 * str The wide-character buffer containing the string or list of strings to
164 * be converted. str_length defines how many wide characters in the
165 * buffer are to be converted, including all desired terminating nul
166 * characters.
167 * str_length Effective length of str
168 * buffer_length Length of buffer
169 * returned_length A pointer to a variable that will receive the number of
170 * narrow characters placed into the buffer. This pointer
171 * may be NULL.
172 */
SQLInstall_narrow(int mode,LPSTR buffer,LPCWSTR str,WORD str_length,WORD buffer_length,WORD * returned_length)173 static BOOL SQLInstall_narrow(int mode, LPSTR buffer, LPCWSTR str, WORD str_length, WORD buffer_length, WORD *returned_length)
174 {
175 LPSTR pbuf; /* allows us to allocate a temporary buffer only if needed */
176 int len; /* Length of the converted list */
177 BOOL success = FALSE;
178 assert(mode == 1 || mode == 2);
179 assert(buffer_length);
180 len = WideCharToMultiByte(CP_ACP, 0, str, str_length, 0, 0, NULL, NULL);
181 if (len > 0)
182 {
183 if (len > buffer_length)
184 {
185 pbuf = HeapAlloc(GetProcessHeap(), 0, len);
186 }
187 else
188 {
189 pbuf = buffer;
190 }
191 len = WideCharToMultiByte(CP_ACP, 0, str, str_length, pbuf, len, NULL, NULL);
192 if (len > 0)
193 {
194 if (pbuf != buffer)
195 {
196 if (buffer_length > (mode - 1))
197 {
198 memcpy (buffer, pbuf, buffer_length-mode);
199 *(buffer+buffer_length-mode) = '\0';
200 }
201 *(buffer+buffer_length-1) = '\0';
202 }
203 if (returned_length)
204 {
205 *returned_length = pbuf == buffer ? len : buffer_length;
206 }
207 success = TRUE;
208 }
209 else
210 {
211 ERR("transferring wide to narrow\n");
212 }
213 if (pbuf != buffer)
214 {
215 HeapFree(GetProcessHeap(), 0, pbuf);
216 }
217 }
218 else
219 {
220 ERR("measuring wide to narrow\n");
221 }
222 return success;
223 }
224
SQLConfigDataSourceW(HWND hwndParent,WORD fRequest,LPCWSTR lpszDriver,LPCWSTR lpszAttributes)225 BOOL WINAPI SQLConfigDataSourceW(HWND hwndParent, WORD fRequest,
226 LPCWSTR lpszDriver, LPCWSTR lpszAttributes)
227 {
228 LPCWSTR p;
229
230 clear_errors();
231 FIXME("%p %d %s %s\n", hwndParent, fRequest, debugstr_w(lpszDriver),
232 debugstr_w(lpszAttributes));
233
234 for (p = lpszAttributes; *p; p += lstrlenW(p) + 1)
235 FIXME("%s\n", debugstr_w(p));
236
237 return TRUE;
238 }
239
SQLConfigDataSource(HWND hwndParent,WORD fRequest,LPCSTR lpszDriver,LPCSTR lpszAttributes)240 BOOL WINAPI SQLConfigDataSource(HWND hwndParent, WORD fRequest,
241 LPCSTR lpszDriver, LPCSTR lpszAttributes)
242 {
243 FIXME("%p %d %s %s\n", hwndParent, fRequest, debugstr_a(lpszDriver),
244 debugstr_a(lpszAttributes));
245 clear_errors();
246 return TRUE;
247 }
248
load_config_driver(const WCHAR * driver)249 static HMODULE load_config_driver(const WCHAR *driver)
250 {
251 static WCHAR reg_driver[] = {'d','r','i','v','e','r',0};
252 long ret;
253 HMODULE hmod;
254 WCHAR *filename = NULL;
255 DWORD size = 0, type;
256 HKEY hkey;
257
258 if ((ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey)) == ERROR_SUCCESS)
259 {
260 HKEY hkeydriver;
261
262 if ((ret = RegOpenKeyW(hkey, driver, &hkeydriver)) == ERROR_SUCCESS)
263 {
264 ret = RegGetValueW(hkeydriver, NULL, reg_driver, RRF_RT_REG_SZ, &type, NULL, &size);
265 if(ret != ERROR_SUCCESS || type != REG_SZ)
266 {
267 RegCloseKey(hkeydriver);
268 RegCloseKey(hkey);
269 push_error(ODBC_ERROR_INVALID_DSN, odbc_error_invalid_dsn);
270
271 return NULL;
272 }
273
274 filename = HeapAlloc(GetProcessHeap(), 0, size);
275 if(!filename)
276 {
277 RegCloseKey(hkeydriver);
278 RegCloseKey(hkey);
279 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
280
281 return NULL;
282 }
283 ret = RegGetValueW(hkeydriver, NULL, reg_driver, RRF_RT_REG_SZ, &type, filename, &size);
284
285 RegCloseKey(hkeydriver);
286 }
287
288 RegCloseKey(hkey);
289 }
290
291 if(ret != ERROR_SUCCESS)
292 {
293 HeapFree(GetProcessHeap(), 0, filename);
294 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
295 return NULL;
296 }
297
298 hmod = LoadLibraryW(filename);
299 HeapFree(GetProcessHeap(), 0, filename);
300
301 if(!hmod)
302 push_error(ODBC_ERROR_LOAD_LIB_FAILED, odbc_error_load_lib_failed);
303
304 return hmod;
305 }
306
write_config_value(const WCHAR * driver,const WCHAR * args)307 static BOOL write_config_value(const WCHAR *driver, const WCHAR *args)
308 {
309 long ret;
310 HKEY hkey, hkeydriver;
311 WCHAR *name = NULL;
312
313 if(!args)
314 return FALSE;
315
316 if((ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey)) == ERROR_SUCCESS)
317 {
318 if((ret = RegOpenKeyW(hkey, driver, &hkeydriver)) == ERROR_SUCCESS)
319 {
320 WCHAR *divider, *value;
321
322 name = heap_alloc( (lstrlenW(args) + 1) * sizeof(WCHAR));
323 if(!name)
324 {
325 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
326 goto fail;
327 }
328 lstrcpyW(name, args);
329
330 divider = wcschr(name,'=');
331 if(!divider)
332 {
333 push_error(ODBC_ERROR_INVALID_KEYWORD_VALUE, odbc_error_invalid_keyword);
334 goto fail;
335 }
336
337 value = divider + 1;
338 *divider = '\0';
339
340 TRACE("Write pair: %s = %s\n", debugstr_w(name), debugstr_w(value));
341 if(RegSetValueExW(hkeydriver, name, 0, REG_SZ, (BYTE*)value,
342 (lstrlenW(value)+1) * sizeof(WCHAR)) != ERROR_SUCCESS)
343 ERR("Failed to write registry installed key\n");
344 heap_free(name);
345
346 RegCloseKey(hkeydriver);
347 }
348
349 RegCloseKey(hkey);
350 }
351
352 if(ret != ERROR_SUCCESS)
353 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
354
355 return ret == ERROR_SUCCESS;
356
357 fail:
358 RegCloseKey(hkeydriver);
359 RegCloseKey(hkey);
360 heap_free(name);
361
362 return FALSE;
363 }
364
SQLConfigDriverW(HWND hwnd,WORD request,LPCWSTR driver,LPCWSTR args,LPWSTR msg,WORD msgmax,WORD * msgout)365 BOOL WINAPI SQLConfigDriverW(HWND hwnd, WORD request, LPCWSTR driver,
366 LPCWSTR args, LPWSTR msg, WORD msgmax, WORD *msgout)
367 {
368 BOOL (WINAPI *pConfigDriverW)(HWND hwnd, WORD request, const WCHAR *driver, const WCHAR *args, const WCHAR *msg, WORD msgmax, WORD *msgout);
369 HMODULE hmod;
370 BOOL funcret = FALSE;
371
372 clear_errors();
373 TRACE("(%p %d %s %s %p %d %p)\n", hwnd, request, debugstr_w(driver),
374 debugstr_w(args), msg, msgmax, msgout);
375
376 if(request == ODBC_CONFIG_DRIVER)
377 {
378 return write_config_value(driver, args);
379 }
380
381 hmod = load_config_driver(driver);
382 if(!hmod)
383 return FALSE;
384
385 pConfigDriverW = (void*)GetProcAddress(hmod, "ConfigDriverW");
386 if(pConfigDriverW)
387 funcret = pConfigDriverW(hwnd, request, driver, args, msg, msgmax, msgout);
388
389 if(!funcret)
390 push_error(ODBC_ERROR_REQUEST_FAILED, odbc_error_request_failed);
391
392 FreeLibrary(hmod);
393
394 return funcret;
395 }
396
SQLConfigDriver(HWND hwnd,WORD request,LPCSTR driver,LPCSTR args,LPSTR msg,WORD msgmax,WORD * msgout)397 BOOL WINAPI SQLConfigDriver(HWND hwnd, WORD request, LPCSTR driver,
398 LPCSTR args, LPSTR msg, WORD msgmax, WORD *msgout)
399 {
400 BOOL (WINAPI *pConfigDriverA)(HWND hwnd, WORD request, const char *driver, const char *args, const char *msg, WORD msgmax, WORD *msgout);
401 HMODULE hmod;
402 WCHAR *driverW;
403 BOOL funcret = FALSE;
404
405 clear_errors();
406 TRACE("(%p %d %s %s %p %d %p)\n", hwnd, request, debugstr_a(driver),
407 debugstr_a(args), msg, msgmax, msgout);
408
409 driverW = heap_strdupAtoW(driver);
410 if(!driverW)
411 {
412 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
413 return FALSE;
414 }
415 if(request == ODBC_CONFIG_DRIVER)
416 {
417 BOOL ret = FALSE;
418 WCHAR *argsW = heap_strdupAtoW(args);
419 if(argsW)
420 {
421 ret = write_config_value(driverW, argsW);
422 HeapFree(GetProcessHeap(), 0, argsW);
423 }
424 else
425 {
426 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
427 }
428
429 HeapFree(GetProcessHeap(), 0, driverW);
430
431 return ret;
432 }
433
434 hmod = load_config_driver(driverW);
435 HeapFree(GetProcessHeap(), 0, driverW);
436 if(!hmod)
437 return FALSE;
438
439 pConfigDriverA = (void*)GetProcAddress(hmod, "ConfigDriver");
440 if(pConfigDriverA)
441 funcret = pConfigDriverA(hwnd, request, driver, args, msg, msgmax, msgout);
442
443 if(!funcret)
444 push_error(ODBC_ERROR_REQUEST_FAILED, odbc_error_request_failed);
445
446 FreeLibrary(hmod);
447
448 return funcret;
449 }
450
SQLCreateDataSourceW(HWND hwnd,LPCWSTR lpszDS)451 BOOL WINAPI SQLCreateDataSourceW(HWND hwnd, LPCWSTR lpszDS)
452 {
453 clear_errors();
454 FIXME("%p %s\n", hwnd, debugstr_w(lpszDS));
455 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
456 return FALSE;
457 }
458
SQLCreateDataSource(HWND hwnd,LPCSTR lpszDS)459 BOOL WINAPI SQLCreateDataSource(HWND hwnd, LPCSTR lpszDS)
460 {
461 clear_errors();
462 FIXME("%p %s\n", hwnd, debugstr_a(lpszDS));
463 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
464 return FALSE;
465 }
466
SQLGetAvailableDriversW(LPCWSTR lpszInfFile,LPWSTR lpszBuf,WORD cbBufMax,WORD * pcbBufOut)467 BOOL WINAPI SQLGetAvailableDriversW(LPCWSTR lpszInfFile, LPWSTR lpszBuf,
468 WORD cbBufMax, WORD *pcbBufOut)
469 {
470 clear_errors();
471 FIXME("%s %p %d %p\n", debugstr_w(lpszInfFile), lpszBuf, cbBufMax, pcbBufOut);
472 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
473 return FALSE;
474 }
475
SQLGetAvailableDrivers(LPCSTR lpszInfFile,LPSTR lpszBuf,WORD cbBufMax,WORD * pcbBufOut)476 BOOL WINAPI SQLGetAvailableDrivers(LPCSTR lpszInfFile, LPSTR lpszBuf,
477 WORD cbBufMax, WORD *pcbBufOut)
478 {
479 clear_errors();
480 FIXME("%s %p %d %p\n", debugstr_a(lpszInfFile), lpszBuf, cbBufMax, pcbBufOut);
481 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
482 return FALSE;
483 }
484
SQLGetConfigMode(UWORD * pwConfigMode)485 BOOL WINAPI SQLGetConfigMode(UWORD *pwConfigMode)
486 {
487 clear_errors();
488 TRACE("%p\n", pwConfigMode);
489 if (pwConfigMode)
490 *pwConfigMode = config_mode;
491 return TRUE;
492 }
493
SQLGetInstalledDriversW(WCHAR * buf,WORD size,WORD * sizeout)494 BOOL WINAPI SQLGetInstalledDriversW(WCHAR *buf, WORD size, WORD *sizeout)
495 {
496 WORD written = 0;
497 DWORD index = 0;
498 BOOL ret = TRUE;
499 DWORD valuelen;
500 WCHAR *value;
501 HKEY drivers;
502 DWORD len;
503 LONG res;
504
505 clear_errors();
506
507 TRACE("%p %d %p\n", buf, size, sizeout);
508
509 if (!buf || !size)
510 {
511 push_error(ODBC_ERROR_INVALID_BUFF_LEN, odbc_error_invalid_buff_len);
512 return FALSE;
513 }
514
515 res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, drivers_key, 0, KEY_QUERY_VALUE, &drivers);
516 if (res)
517 {
518 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
519 return FALSE;
520 }
521
522 valuelen = 256;
523 value = heap_alloc(valuelen * sizeof(WCHAR));
524
525 size--;
526
527 while (1)
528 {
529 len = valuelen;
530 res = RegEnumValueW(drivers, index, value, &len, NULL, NULL, NULL, NULL);
531 while (res == ERROR_MORE_DATA)
532 {
533 value = heap_realloc(value, ++len * sizeof(WCHAR));
534 res = RegEnumValueW(drivers, index, value, &len, NULL, NULL, NULL, NULL);
535 }
536 if (res == ERROR_SUCCESS)
537 {
538 lstrcpynW(buf + written, value, size - written);
539 written += min(len + 1, size - written);
540 }
541 else if (res == ERROR_NO_MORE_ITEMS)
542 break;
543 else
544 {
545 push_error(ODBC_ERROR_GENERAL_ERR, odbc_error_general_err);
546 ret = FALSE;
547 break;
548 }
549 index++;
550 }
551
552 buf[written++] = 0;
553
554 heap_free(value);
555 RegCloseKey(drivers);
556 if (sizeout)
557 *sizeout = written;
558 return ret;
559 }
560
SQLGetInstalledDrivers(char * buf,WORD size,WORD * sizeout)561 BOOL WINAPI SQLGetInstalledDrivers(char *buf, WORD size, WORD *sizeout)
562 {
563 WORD written;
564 WCHAR *wbuf;
565 BOOL ret;
566
567 TRACE("%p %d %p\n", buf, size, sizeout);
568
569 if (!buf || !size)
570 {
571 push_error(ODBC_ERROR_INVALID_BUFF_LEN, odbc_error_invalid_buff_len);
572 return FALSE;
573 }
574
575 wbuf = heap_alloc(size * sizeof(WCHAR));
576 if (!wbuf)
577 {
578 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
579 return FALSE;
580 }
581
582 ret = SQLGetInstalledDriversW(wbuf, size, &written);
583 if (!ret)
584 {
585 heap_free(wbuf);
586 return FALSE;
587 }
588
589 *sizeout = WideCharToMultiByte(CP_ACP, 0, wbuf, written, NULL, 0, NULL, NULL);
590 WideCharToMultiByte(CP_ACP, 0, wbuf, written, buf, size, NULL, NULL);
591
592 heap_free(wbuf);
593 return TRUE;
594 }
595
get_privateprofile_sectionkey(LPCWSTR section,LPCWSTR filename)596 static HKEY get_privateprofile_sectionkey(LPCWSTR section, LPCWSTR filename)
597 {
598 HKEY hkey, hkeyfilename, hkeysection;
599 LONG ret;
600
601 if (RegOpenKeyW(HKEY_CURRENT_USER, odbcW, &hkey))
602 return NULL;
603
604 ret = RegOpenKeyW(hkey, filename, &hkeyfilename);
605 RegCloseKey(hkey);
606 if (ret)
607 return NULL;
608
609 ret = RegOpenKeyW(hkeyfilename, section, &hkeysection);
610 RegCloseKey(hkeyfilename);
611
612 return ret ? NULL : hkeysection;
613 }
614
SQLGetPrivateProfileStringW(LPCWSTR section,LPCWSTR entry,LPCWSTR defvalue,LPWSTR buff,int buff_len,LPCWSTR filename)615 int WINAPI SQLGetPrivateProfileStringW(LPCWSTR section, LPCWSTR entry,
616 LPCWSTR defvalue, LPWSTR buff, int buff_len, LPCWSTR filename)
617 {
618 BOOL usedefault = TRUE;
619 HKEY sectionkey;
620 LONG ret = 0;
621
622 TRACE("%s %s %s %p %d %s\n", debugstr_w(section), debugstr_w(entry),
623 debugstr_w(defvalue), buff, buff_len, debugstr_w(filename));
624
625 clear_errors();
626
627 if (buff_len <= 0 || !section)
628 return 0;
629
630 if(buff)
631 buff[0] = 0;
632
633 if (!defvalue || !buff)
634 return 0;
635
636 sectionkey = get_privateprofile_sectionkey(section, filename);
637 if (sectionkey)
638 {
639 DWORD type, size;
640
641 if (entry)
642 {
643 size = buff_len * sizeof(*buff);
644 if (RegGetValueW(sectionkey, NULL, entry, RRF_RT_REG_SZ, &type, buff, &size) == ERROR_SUCCESS)
645 {
646 usedefault = FALSE;
647 ret = (size / sizeof(*buff)) - 1;
648 }
649 }
650 else
651 {
652 WCHAR name[MAX_PATH];
653 DWORD index = 0;
654 DWORD namelen;
655
656 usedefault = FALSE;
657
658 memset(buff, 0, buff_len);
659
660 namelen = sizeof(name);
661 while (RegEnumValueW(sectionkey, index, name, &namelen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
662 {
663 if ((ret + namelen+1) > buff_len)
664 break;
665
666 lstrcpyW(buff+ret, name);
667 ret += namelen+1;
668 namelen = sizeof(name);
669 index++;
670 }
671 }
672
673 RegCloseKey(sectionkey);
674 }
675 else
676 usedefault = entry != NULL;
677
678 if (usedefault)
679 {
680 lstrcpynW(buff, defvalue, buff_len);
681 ret = lstrlenW(buff);
682 }
683
684 return ret;
685 }
686
SQLGetPrivateProfileString(LPCSTR section,LPCSTR entry,LPCSTR defvalue,LPSTR buff,int buff_len,LPCSTR filename)687 int WINAPI SQLGetPrivateProfileString(LPCSTR section, LPCSTR entry,
688 LPCSTR defvalue, LPSTR buff, int buff_len, LPCSTR filename)
689 {
690 WCHAR *sectionW, *filenameW;
691 BOOL usedefault = TRUE;
692 HKEY sectionkey;
693 LONG ret = 0;
694
695 TRACE("%s %s %s %p %d %s\n", debugstr_a(section), debugstr_a(entry),
696 debugstr_a(defvalue), buff, buff_len, debugstr_a(filename));
697
698 clear_errors();
699
700 if (buff_len <= 0)
701 return 0;
702
703 if (buff)
704 buff[0] = 0;
705
706 if (!section || !defvalue || !buff)
707 return 0;
708
709 sectionW = heap_strdupAtoW(section);
710 filenameW = heap_strdupAtoW(filename);
711
712 sectionkey = get_privateprofile_sectionkey(sectionW, filenameW);
713
714 heap_free(sectionW);
715 heap_free(filenameW);
716
717 if (sectionkey)
718 {
719 DWORD type, size;
720
721 if (entry)
722 {
723 size = buff_len * sizeof(*buff);
724 if (RegGetValueA(sectionkey, NULL, entry, RRF_RT_REG_SZ, &type, buff, &size) == ERROR_SUCCESS)
725 {
726 usedefault = FALSE;
727 ret = (size / sizeof(*buff)) - 1;
728 }
729 }
730 else
731 {
732 char name[MAX_PATH] = {0};
733 DWORD index = 0;
734 DWORD namelen;
735
736 usedefault = FALSE;
737
738 memset(buff, 0, buff_len);
739
740 namelen = sizeof(name);
741 while (RegEnumValueA(sectionkey, index, name, &namelen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
742 {
743 if ((ret + namelen+1) > buff_len)
744 break;
745
746 lstrcpyA(buff+ret, name);
747
748 ret += namelen+1;
749 namelen = sizeof(name);
750 index++;
751 }
752 }
753
754 RegCloseKey(sectionkey);
755 }
756 else
757 usedefault = entry != NULL;
758
759 if (usedefault)
760 {
761 lstrcpynA(buff, defvalue, buff_len);
762 ret = strlen(buff);
763 }
764
765 return ret;
766 }
767
SQLGetTranslatorW(HWND hwndParent,LPWSTR lpszName,WORD cbNameMax,WORD * pcbNameOut,LPWSTR lpszPath,WORD cbPathMax,WORD * pcbPathOut,DWORD * pvOption)768 BOOL WINAPI SQLGetTranslatorW(HWND hwndParent, LPWSTR lpszName, WORD cbNameMax,
769 WORD *pcbNameOut, LPWSTR lpszPath, WORD cbPathMax,
770 WORD *pcbPathOut, DWORD *pvOption)
771 {
772 clear_errors();
773 FIXME("%p %s %d %p %p %d %p %p\n", hwndParent, debugstr_w(lpszName), cbNameMax,
774 pcbNameOut, lpszPath, cbPathMax, pcbPathOut, pvOption);
775 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
776 return FALSE;
777 }
778
SQLGetTranslator(HWND hwndParent,LPSTR lpszName,WORD cbNameMax,WORD * pcbNameOut,LPSTR lpszPath,WORD cbPathMax,WORD * pcbPathOut,DWORD * pvOption)779 BOOL WINAPI SQLGetTranslator(HWND hwndParent, LPSTR lpszName, WORD cbNameMax,
780 WORD *pcbNameOut, LPSTR lpszPath, WORD cbPathMax,
781 WORD *pcbPathOut, DWORD *pvOption)
782 {
783 clear_errors();
784 FIXME("%p %s %d %p %p %d %p %p\n", hwndParent, debugstr_a(lpszName), cbNameMax,
785 pcbNameOut, lpszPath, cbPathMax, pcbPathOut, pvOption);
786 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
787 return FALSE;
788 }
789
SQLInstallDriverW(LPCWSTR lpszInfFile,LPCWSTR lpszDriver,LPWSTR lpszPath,WORD cbPathMax,WORD * pcbPathOut)790 BOOL WINAPI SQLInstallDriverW(LPCWSTR lpszInfFile, LPCWSTR lpszDriver,
791 LPWSTR lpszPath, WORD cbPathMax, WORD * pcbPathOut)
792 {
793 DWORD usage;
794
795 clear_errors();
796 TRACE("%s %s %p %d %p\n", debugstr_w(lpszInfFile),
797 debugstr_w(lpszDriver), lpszPath, cbPathMax, pcbPathOut);
798
799 if (lpszInfFile)
800 return FALSE;
801
802 return SQLInstallDriverExW(lpszDriver, NULL, lpszPath, cbPathMax,
803 pcbPathOut, ODBC_INSTALL_COMPLETE, &usage);
804 }
805
SQLInstallDriver(LPCSTR lpszInfFile,LPCSTR lpszDriver,LPSTR lpszPath,WORD cbPathMax,WORD * pcbPathOut)806 BOOL WINAPI SQLInstallDriver(LPCSTR lpszInfFile, LPCSTR lpszDriver,
807 LPSTR lpszPath, WORD cbPathMax, WORD * pcbPathOut)
808 {
809 DWORD usage;
810
811 clear_errors();
812 TRACE("%s %s %p %d %p\n", debugstr_a(lpszInfFile),
813 debugstr_a(lpszDriver), lpszPath, cbPathMax, pcbPathOut);
814
815 if (lpszInfFile)
816 return FALSE;
817
818 return SQLInstallDriverEx(lpszDriver, NULL, lpszPath, cbPathMax,
819 pcbPathOut, ODBC_INSTALL_COMPLETE, &usage);
820 }
821
write_registry_values(const WCHAR * regkey,const WCHAR * driver,const WCHAR * path_in,WCHAR * path,DWORD * usage_count)822 static void write_registry_values(const WCHAR *regkey, const WCHAR *driver, const WCHAR *path_in, WCHAR *path,
823 DWORD *usage_count)
824 {
825 static const WCHAR installed[] = {'I','n','s','t','a','l','l','e','d',0};
826 static const WCHAR slash[] = {'\\', 0};
827 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
828 static const WCHAR setupW[] = {'S','e','t','u','p',0};
829 static const WCHAR translator[] = {'T','r','a','n','s','l','a','t','o','r',0};
830 HKEY hkey, hkeydriver;
831
832 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey) == ERROR_SUCCESS)
833 {
834 if (RegCreateKeyW(hkey, regkey, &hkeydriver) == ERROR_SUCCESS)
835 {
836 if(RegSetValueExW(hkeydriver, driver, 0, REG_SZ, (BYTE*)installed, sizeof(installed)) != ERROR_SUCCESS)
837 ERR("Failed to write registry installed key\n");
838
839 RegCloseKey(hkeydriver);
840 }
841
842 if (RegCreateKeyW(hkey, driver, &hkeydriver) == ERROR_SUCCESS)
843 {
844 WCHAR entry[1024];
845 const WCHAR *p;
846 DWORD usagecount = 0;
847 DWORD type, size;
848
849 /* Skip name entry */
850 p = driver;
851 p += lstrlenW(p) + 1;
852
853 if (!path_in)
854 GetSystemDirectoryW(path, MAX_PATH);
855 else
856 lstrcpyW(path, path_in);
857
858 /* Store Usage */
859 size = sizeof(usagecount);
860 RegGetValueA(hkeydriver, NULL, "UsageCount", RRF_RT_DWORD, &type, &usagecount, &size);
861 TRACE("Usage count %d\n", usagecount);
862
863 for (; *p; p += lstrlenW(p) + 1)
864 {
865 WCHAR *divider = wcschr(p,'=');
866
867 if (divider)
868 {
869 WCHAR *value;
870 int len;
871
872 /* Write pair values to the registry. */
873 lstrcpynW(entry, p, divider - p + 1);
874
875 divider++;
876 TRACE("Writing pair %s,%s\n", debugstr_w(entry), debugstr_w(divider));
877
878 /* Driver, Setup, Translator entries use the system path unless a path is specified. */
879 if(lstrcmpiW(driverW, entry) == 0 || lstrcmpiW(setupW, entry) == 0 ||
880 lstrcmpiW(translator, entry) == 0)
881 {
882 len = lstrlenW(path) + lstrlenW(slash) + lstrlenW(divider) + 1;
883 value = heap_alloc(len * sizeof(WCHAR));
884 if(!value)
885 {
886 ERR("Out of memory\n");
887 return;
888 }
889
890 lstrcpyW(value, path);
891 lstrcatW(value, slash);
892 lstrcatW(value, divider);
893 }
894 else
895 {
896 len = lstrlenW(divider) + 1;
897 value = heap_alloc(len * sizeof(WCHAR));
898 lstrcpyW(value, divider);
899 }
900
901 if (RegSetValueExW(hkeydriver, entry, 0, REG_SZ, (BYTE*)value,
902 (lstrlenW(value)+1)*sizeof(WCHAR)) != ERROR_SUCCESS)
903 ERR("Failed to write registry data %s %s\n", debugstr_w(entry), debugstr_w(value));
904 heap_free(value);
905 }
906 else
907 {
908 ERR("No pair found. %s\n", debugstr_w(p));
909 break;
910 }
911 }
912
913 /* Set Usage Count */
914 usagecount++;
915 if (RegSetValueExA(hkeydriver, "UsageCount", 0, REG_DWORD, (BYTE*)&usagecount, sizeof(usagecount)) != ERROR_SUCCESS)
916 ERR("Failed to write registry UsageCount key\n");
917
918 if (usage_count)
919 *usage_count = usagecount;
920
921 RegCloseKey(hkeydriver);
922 }
923
924 RegCloseKey(hkey);
925 }
926 }
927
SQLInstallDriverExW(LPCWSTR lpszDriver,LPCWSTR lpszPathIn,LPWSTR lpszPathOut,WORD cbPathOutMax,WORD * pcbPathOut,WORD fRequest,LPDWORD lpdwUsageCount)928 BOOL WINAPI SQLInstallDriverExW(LPCWSTR lpszDriver, LPCWSTR lpszPathIn,
929 LPWSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
930 WORD fRequest, LPDWORD lpdwUsageCount)
931 {
932 UINT len;
933 WCHAR path[MAX_PATH];
934
935 clear_errors();
936 TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszDriver),
937 debugstr_w(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
938 fRequest, lpdwUsageCount);
939
940 write_registry_values(odbcdrivers, lpszDriver, lpszPathIn, path, lpdwUsageCount);
941
942 len = lstrlenW(path);
943
944 if (pcbPathOut)
945 *pcbPathOut = len;
946
947 if (lpszPathOut && cbPathOutMax > len)
948 {
949 lstrcpyW(lpszPathOut, path);
950 return TRUE;
951 }
952 return FALSE;
953 }
954
SQLInstallDriverEx(LPCSTR lpszDriver,LPCSTR lpszPathIn,LPSTR lpszPathOut,WORD cbPathOutMax,WORD * pcbPathOut,WORD fRequest,LPDWORD lpdwUsageCount)955 BOOL WINAPI SQLInstallDriverEx(LPCSTR lpszDriver, LPCSTR lpszPathIn,
956 LPSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
957 WORD fRequest, LPDWORD lpdwUsageCount)
958 {
959 LPWSTR driver, pathin;
960 WCHAR pathout[MAX_PATH];
961 BOOL ret;
962 WORD cbOut = 0;
963
964 clear_errors();
965 TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszDriver),
966 debugstr_a(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
967 fRequest, lpdwUsageCount);
968
969 driver = SQLInstall_strdup_multi(lpszDriver);
970 pathin = SQLInstall_strdup(lpszPathIn);
971
972 ret = SQLInstallDriverExW(driver, pathin, pathout, MAX_PATH, &cbOut,
973 fRequest, lpdwUsageCount);
974 if (ret)
975 {
976 int len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
977 0, NULL, NULL);
978 if (len)
979 {
980 if (pcbPathOut)
981 *pcbPathOut = len - 1;
982
983 if (!lpszPathOut || cbPathOutMax < len)
984 {
985 ret = FALSE;
986 goto out;
987 }
988 len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
989 cbPathOutMax, NULL, NULL);
990 }
991 }
992
993 out:
994 HeapFree(GetProcessHeap(), 0, driver);
995 HeapFree(GetProcessHeap(), 0, pathin);
996 return ret;
997 }
998
SQLInstallDriverManagerW(LPWSTR lpszPath,WORD cbPathMax,WORD * pcbPathOut)999 BOOL WINAPI SQLInstallDriverManagerW(LPWSTR lpszPath, WORD cbPathMax,
1000 WORD *pcbPathOut)
1001 {
1002 UINT len;
1003 WCHAR path[MAX_PATH];
1004
1005 TRACE("(%p %d %p)\n", lpszPath, cbPathMax, pcbPathOut);
1006
1007 if (cbPathMax < MAX_PATH)
1008 return FALSE;
1009
1010 clear_errors();
1011
1012 len = GetSystemDirectoryW(path, MAX_PATH);
1013
1014 if (pcbPathOut)
1015 *pcbPathOut = len;
1016
1017 if (lpszPath && cbPathMax > len)
1018 {
1019 lstrcpyW(lpszPath, path);
1020 return TRUE;
1021 }
1022 return FALSE;
1023 }
1024
SQLInstallDriverManager(LPSTR lpszPath,WORD cbPathMax,WORD * pcbPathOut)1025 BOOL WINAPI SQLInstallDriverManager(LPSTR lpszPath, WORD cbPathMax,
1026 WORD *pcbPathOut)
1027 {
1028 BOOL ret;
1029 WORD len, cbOut = 0;
1030 WCHAR path[MAX_PATH];
1031
1032 TRACE("(%p %d %p)\n", lpszPath, cbPathMax, pcbPathOut);
1033
1034 if (cbPathMax < MAX_PATH)
1035 return FALSE;
1036
1037 clear_errors();
1038
1039 ret = SQLInstallDriverManagerW(path, MAX_PATH, &cbOut);
1040 if (ret)
1041 {
1042 len = WideCharToMultiByte(CP_ACP, 0, path, -1, lpszPath, 0,
1043 NULL, NULL);
1044 if (len)
1045 {
1046 if (pcbPathOut)
1047 *pcbPathOut = len - 1;
1048
1049 if (!lpszPath || cbPathMax < len)
1050 return FALSE;
1051
1052 len = WideCharToMultiByte(CP_ACP, 0, path, -1, lpszPath,
1053 cbPathMax, NULL, NULL);
1054 }
1055 }
1056 return ret;
1057 }
1058
SQLInstallODBCW(HWND hwndParent,LPCWSTR lpszInfFile,LPCWSTR lpszSrcPath,LPCWSTR lpszDrivers)1059 BOOL WINAPI SQLInstallODBCW(HWND hwndParent, LPCWSTR lpszInfFile,
1060 LPCWSTR lpszSrcPath, LPCWSTR lpszDrivers)
1061 {
1062 clear_errors();
1063 FIXME("%p %s %s %s\n", hwndParent, debugstr_w(lpszInfFile),
1064 debugstr_w(lpszSrcPath), debugstr_w(lpszDrivers));
1065 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1066 return FALSE;
1067 }
1068
SQLInstallODBC(HWND hwndParent,LPCSTR lpszInfFile,LPCSTR lpszSrcPath,LPCSTR lpszDrivers)1069 BOOL WINAPI SQLInstallODBC(HWND hwndParent, LPCSTR lpszInfFile,
1070 LPCSTR lpszSrcPath, LPCSTR lpszDrivers)
1071 {
1072 clear_errors();
1073 FIXME("%p %s %s %s\n", hwndParent, debugstr_a(lpszInfFile),
1074 debugstr_a(lpszSrcPath), debugstr_a(lpszDrivers));
1075 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1076 return FALSE;
1077 }
1078
SQLInstallerErrorW(WORD iError,DWORD * pfErrorCode,LPWSTR lpszErrorMsg,WORD cbErrorMsgMax,WORD * pcbErrorMsg)1079 SQLRETURN WINAPI SQLInstallerErrorW(WORD iError, DWORD *pfErrorCode,
1080 LPWSTR lpszErrorMsg, WORD cbErrorMsgMax, WORD *pcbErrorMsg)
1081 {
1082 TRACE("%d %p %p %d %p\n", iError, pfErrorCode, lpszErrorMsg,
1083 cbErrorMsgMax, pcbErrorMsg);
1084
1085 if (iError == 0)
1086 {
1087 return SQL_ERROR;
1088 }
1089 else if (iError <= num_errors)
1090 {
1091 BOOL truncated = FALSE;
1092 WORD len;
1093 LPCWSTR msg;
1094 iError--;
1095 if (pfErrorCode)
1096 *pfErrorCode = error_code[iError];
1097 msg = error_msg[iError];
1098 len = msg ? lstrlenW(msg) : 0;
1099 if (pcbErrorMsg)
1100 *pcbErrorMsg = len;
1101 len++;
1102 if (cbErrorMsgMax < len)
1103 {
1104 len = cbErrorMsgMax;
1105 truncated = TRUE;
1106 }
1107 if (lpszErrorMsg && len)
1108 {
1109 if (msg)
1110 {
1111 memcpy (lpszErrorMsg, msg, len * sizeof(WCHAR));
1112 }
1113 else
1114 {
1115 assert(len==1);
1116 *lpszErrorMsg = 0;
1117 }
1118 }
1119 else
1120 {
1121 /* Yes. If you pass a null pointer and a large length it is not an error! */
1122 truncated = TRUE;
1123 }
1124
1125 return truncated ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
1126 }
1127
1128 /* At least on Windows 2000 , the buffers are not altered in this case. However that is a little too dangerous a test for just now */
1129 if (pcbErrorMsg)
1130 *pcbErrorMsg = 0;
1131
1132 if (lpszErrorMsg && cbErrorMsgMax > 0)
1133 *lpszErrorMsg = '\0';
1134
1135 return SQL_NO_DATA;
1136 }
1137
SQLInstallerError(WORD iError,DWORD * pfErrorCode,LPSTR lpszErrorMsg,WORD cbErrorMsgMax,WORD * pcbErrorMsg)1138 SQLRETURN WINAPI SQLInstallerError(WORD iError, DWORD *pfErrorCode,
1139 LPSTR lpszErrorMsg, WORD cbErrorMsgMax, WORD *pcbErrorMsg)
1140 {
1141 SQLRETURN ret;
1142 LPWSTR wbuf;
1143 WORD cbwbuf;
1144 TRACE("%d %p %p %d %p\n", iError, pfErrorCode, lpszErrorMsg,
1145 cbErrorMsgMax, pcbErrorMsg);
1146
1147 wbuf = 0;
1148 if (lpszErrorMsg && cbErrorMsgMax)
1149 {
1150 wbuf = HeapAlloc(GetProcessHeap(), 0, cbErrorMsgMax*sizeof(WCHAR));
1151 if (!wbuf)
1152 return SQL_ERROR;
1153 }
1154 ret = SQLInstallerErrorW(iError, pfErrorCode, wbuf, cbErrorMsgMax, &cbwbuf);
1155 if (wbuf)
1156 {
1157 WORD cbBuf = 0;
1158 SQLInstall_narrow(1, lpszErrorMsg, wbuf, cbwbuf+1, cbErrorMsgMax, &cbBuf);
1159 HeapFree(GetProcessHeap(), 0, wbuf);
1160 if (pcbErrorMsg)
1161 *pcbErrorMsg = cbBuf-1;
1162 }
1163 return ret;
1164 }
1165
SQLInstallTranslatorExW(LPCWSTR lpszTranslator,LPCWSTR lpszPathIn,LPWSTR lpszPathOut,WORD cbPathOutMax,WORD * pcbPathOut,WORD fRequest,LPDWORD lpdwUsageCount)1166 BOOL WINAPI SQLInstallTranslatorExW(LPCWSTR lpszTranslator, LPCWSTR lpszPathIn,
1167 LPWSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
1168 WORD fRequest, LPDWORD lpdwUsageCount)
1169 {
1170 UINT len;
1171 WCHAR path[MAX_PATH];
1172
1173 clear_errors();
1174 TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszTranslator),
1175 debugstr_w(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
1176 fRequest, lpdwUsageCount);
1177
1178 write_registry_values(odbctranslators, lpszTranslator, lpszPathIn, path, lpdwUsageCount);
1179
1180 len = lstrlenW(path);
1181
1182 if (pcbPathOut)
1183 *pcbPathOut = len;
1184
1185 if (lpszPathOut && cbPathOutMax > len)
1186 {
1187 lstrcpyW(lpszPathOut, path);
1188 return TRUE;
1189 }
1190 return FALSE;
1191 }
1192
SQLInstallTranslatorEx(LPCSTR lpszTranslator,LPCSTR lpszPathIn,LPSTR lpszPathOut,WORD cbPathOutMax,WORD * pcbPathOut,WORD fRequest,LPDWORD lpdwUsageCount)1193 BOOL WINAPI SQLInstallTranslatorEx(LPCSTR lpszTranslator, LPCSTR lpszPathIn,
1194 LPSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
1195 WORD fRequest, LPDWORD lpdwUsageCount)
1196 {
1197 LPCSTR p;
1198 LPWSTR translator, pathin;
1199 WCHAR pathout[MAX_PATH];
1200 BOOL ret;
1201 WORD cbOut = 0;
1202
1203 clear_errors();
1204 TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszTranslator),
1205 debugstr_a(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
1206 fRequest, lpdwUsageCount);
1207
1208 for (p = lpszTranslator; *p; p += lstrlenA(p) + 1)
1209 TRACE("%s\n", debugstr_a(p));
1210
1211 translator = SQLInstall_strdup_multi(lpszTranslator);
1212 pathin = SQLInstall_strdup(lpszPathIn);
1213
1214 ret = SQLInstallTranslatorExW(translator, pathin, pathout, MAX_PATH,
1215 &cbOut, fRequest, lpdwUsageCount);
1216 if (ret)
1217 {
1218 int len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
1219 0, NULL, NULL);
1220 if (len)
1221 {
1222 if (pcbPathOut)
1223 *pcbPathOut = len - 1;
1224
1225 if (!lpszPathOut || cbPathOutMax < len)
1226 {
1227 ret = FALSE;
1228 goto out;
1229 }
1230 len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
1231 cbPathOutMax, NULL, NULL);
1232 }
1233 }
1234
1235 out:
1236 HeapFree(GetProcessHeap(), 0, translator);
1237 HeapFree(GetProcessHeap(), 0, pathin);
1238 return ret;
1239 }
1240
SQLInstallTranslator(LPCSTR lpszInfFile,LPCSTR lpszTranslator,LPCSTR lpszPathIn,LPSTR lpszPathOut,WORD cbPathOutMax,WORD * pcbPathOut,WORD fRequest,LPDWORD lpdwUsageCount)1241 BOOL WINAPI SQLInstallTranslator(LPCSTR lpszInfFile, LPCSTR lpszTranslator,
1242 LPCSTR lpszPathIn, LPSTR lpszPathOut, WORD cbPathOutMax,
1243 WORD *pcbPathOut, WORD fRequest, LPDWORD lpdwUsageCount)
1244 {
1245 clear_errors();
1246 TRACE("%s %s %s %p %d %p %d %p\n", debugstr_a(lpszInfFile),
1247 debugstr_a(lpszTranslator), debugstr_a(lpszPathIn), lpszPathOut,
1248 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
1249
1250 if (lpszInfFile)
1251 return FALSE;
1252
1253 return SQLInstallTranslatorEx(lpszTranslator, lpszPathIn, lpszPathOut,
1254 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
1255 }
1256
SQLInstallTranslatorW(LPCWSTR lpszInfFile,LPCWSTR lpszTranslator,LPCWSTR lpszPathIn,LPWSTR lpszPathOut,WORD cbPathOutMax,WORD * pcbPathOut,WORD fRequest,LPDWORD lpdwUsageCount)1257 BOOL WINAPI SQLInstallTranslatorW(LPCWSTR lpszInfFile, LPCWSTR lpszTranslator,
1258 LPCWSTR lpszPathIn, LPWSTR lpszPathOut, WORD cbPathOutMax,
1259 WORD *pcbPathOut, WORD fRequest, LPDWORD lpdwUsageCount)
1260 {
1261 clear_errors();
1262 TRACE("%s %s %s %p %d %p %d %p\n", debugstr_w(lpszInfFile),
1263 debugstr_w(lpszTranslator), debugstr_w(lpszPathIn), lpszPathOut,
1264 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
1265
1266 if (lpszInfFile)
1267 return FALSE;
1268
1269 return SQLInstallTranslatorExW(lpszTranslator, lpszPathIn, lpszPathOut,
1270 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
1271 }
1272
SQLManageDataSources(HWND hwnd)1273 BOOL WINAPI SQLManageDataSources(HWND hwnd)
1274 {
1275 clear_errors();
1276 FIXME("%p\n", hwnd);
1277 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1278 return FALSE;
1279 }
1280
SQLPostInstallerErrorW(DWORD fErrorCode,LPCWSTR szErrorMsg)1281 SQLRETURN WINAPI SQLPostInstallerErrorW(DWORD fErrorCode, LPCWSTR szErrorMsg)
1282 {
1283 FIXME("%u %s\n", fErrorCode, debugstr_w(szErrorMsg));
1284 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1285 return FALSE;
1286 }
1287
SQLPostInstallerError(DWORD fErrorCode,LPCSTR szErrorMsg)1288 SQLRETURN WINAPI SQLPostInstallerError(DWORD fErrorCode, LPCSTR szErrorMsg)
1289 {
1290 FIXME("%u %s\n", fErrorCode, debugstr_a(szErrorMsg));
1291 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1292 return FALSE;
1293 }
1294
SQLReadFileDSNW(LPCWSTR lpszFileName,LPCWSTR lpszAppName,LPCWSTR lpszKeyName,LPWSTR lpszString,WORD cbString,WORD * pcbString)1295 BOOL WINAPI SQLReadFileDSNW(LPCWSTR lpszFileName, LPCWSTR lpszAppName,
1296 LPCWSTR lpszKeyName, LPWSTR lpszString, WORD cbString,
1297 WORD *pcbString)
1298 {
1299 clear_errors();
1300 FIXME("%s %s %s %s %d %p\n", debugstr_w(lpszFileName), debugstr_w(lpszAppName),
1301 debugstr_w(lpszKeyName), debugstr_w(lpszString), cbString, pcbString);
1302 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1303 return FALSE;
1304 }
1305
SQLReadFileDSN(LPCSTR lpszFileName,LPCSTR lpszAppName,LPCSTR lpszKeyName,LPSTR lpszString,WORD cbString,WORD * pcbString)1306 BOOL WINAPI SQLReadFileDSN(LPCSTR lpszFileName, LPCSTR lpszAppName,
1307 LPCSTR lpszKeyName, LPSTR lpszString, WORD cbString,
1308 WORD *pcbString)
1309 {
1310 clear_errors();
1311 FIXME("%s %s %s %s %d %p\n", debugstr_a(lpszFileName), debugstr_a(lpszAppName),
1312 debugstr_a(lpszKeyName), debugstr_a(lpszString), cbString, pcbString);
1313 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1314 return FALSE;
1315 }
1316
SQLRemoveDefaultDataSource(void)1317 BOOL WINAPI SQLRemoveDefaultDataSource(void)
1318 {
1319 clear_errors();
1320 FIXME("\n");
1321 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1322 return FALSE;
1323 }
1324
SQLRemoveDriverW(LPCWSTR drivername,BOOL remove_dsn,LPDWORD usage_count)1325 BOOL WINAPI SQLRemoveDriverW(LPCWSTR drivername, BOOL remove_dsn, LPDWORD usage_count)
1326 {
1327 HKEY hkey;
1328 DWORD usagecount = 1;
1329
1330 clear_errors();
1331 TRACE("%s %d %p\n", debugstr_w(drivername), remove_dsn, usage_count);
1332
1333 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey) == ERROR_SUCCESS)
1334 {
1335 HKEY hkeydriver;
1336
1337 if (RegOpenKeyW(hkey, drivername, &hkeydriver) == ERROR_SUCCESS)
1338 {
1339 DWORD size, type;
1340 DWORD count;
1341
1342 size = sizeof(usagecount);
1343 RegGetValueA(hkeydriver, NULL, "UsageCount", RRF_RT_DWORD, &type, &usagecount, &size);
1344 TRACE("Usage count %d\n", usagecount);
1345 count = usagecount - 1;
1346 if (count)
1347 {
1348 if (RegSetValueExA(hkeydriver, "UsageCount", 0, REG_DWORD, (BYTE*)&count, sizeof(count)) != ERROR_SUCCESS)
1349 ERR("Failed to write registry UsageCount key\n");
1350 }
1351
1352 RegCloseKey(hkeydriver);
1353 }
1354
1355 if (usagecount)
1356 usagecount--;
1357
1358 if (!usagecount)
1359 {
1360 if (RegDeleteKeyW(hkey, drivername) != ERROR_SUCCESS)
1361 ERR("Failed to delete registry key: %s\n", debugstr_w(drivername));
1362
1363 if (RegOpenKeyW(hkey, odbcdrivers, &hkeydriver) == ERROR_SUCCESS)
1364 {
1365 if(RegDeleteValueW(hkeydriver, drivername) != ERROR_SUCCESS)
1366 ERR("Failed to delete registry value: %s\n", debugstr_w(drivername));
1367 RegCloseKey(hkeydriver);
1368 }
1369 }
1370
1371 RegCloseKey(hkey);
1372 }
1373
1374 if (usage_count)
1375 *usage_count = usagecount;
1376
1377 return TRUE;
1378 }
1379
SQLRemoveDriver(LPCSTR lpszDriver,BOOL fRemoveDSN,LPDWORD lpdwUsageCount)1380 BOOL WINAPI SQLRemoveDriver(LPCSTR lpszDriver, BOOL fRemoveDSN,
1381 LPDWORD lpdwUsageCount)
1382 {
1383 WCHAR *driver;
1384 BOOL ret;
1385
1386 clear_errors();
1387 TRACE("%s %d %p\n", debugstr_a(lpszDriver), fRemoveDSN, lpdwUsageCount);
1388
1389 driver = SQLInstall_strdup(lpszDriver);
1390
1391 ret = SQLRemoveDriverW(driver, fRemoveDSN, lpdwUsageCount);
1392
1393 HeapFree(GetProcessHeap(), 0, driver);
1394 return ret;
1395 }
1396
SQLRemoveDriverManager(LPDWORD pdwUsageCount)1397 BOOL WINAPI SQLRemoveDriverManager(LPDWORD pdwUsageCount)
1398 {
1399 clear_errors();
1400 FIXME("%p\n", pdwUsageCount);
1401 if (pdwUsageCount) *pdwUsageCount = 1;
1402 return TRUE;
1403 }
1404
SQLRemoveDSNFromIniW(LPCWSTR lpszDSN)1405 BOOL WINAPI SQLRemoveDSNFromIniW(LPCWSTR lpszDSN)
1406 {
1407 clear_errors();
1408 FIXME("%s\n", debugstr_w(lpszDSN));
1409 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1410 return FALSE;
1411 }
1412
SQLRemoveDSNFromIni(LPCSTR lpszDSN)1413 BOOL WINAPI SQLRemoveDSNFromIni(LPCSTR lpszDSN)
1414 {
1415 clear_errors();
1416 FIXME("%s\n", debugstr_a(lpszDSN));
1417 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1418 return FALSE;
1419 }
1420
SQLRemoveTranslatorW(const WCHAR * translator,DWORD * usage_count)1421 BOOL WINAPI SQLRemoveTranslatorW(const WCHAR *translator, DWORD *usage_count)
1422 {
1423 HKEY hkey;
1424 DWORD usagecount = 1;
1425 BOOL ret = TRUE;
1426
1427 clear_errors();
1428 TRACE("%s %p\n", debugstr_w(translator), usage_count);
1429
1430 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey) == ERROR_SUCCESS)
1431 {
1432 HKEY hkeydriver;
1433
1434 if (RegOpenKeyW(hkey, translator, &hkeydriver) == ERROR_SUCCESS)
1435 {
1436 DWORD size, type;
1437 DWORD count;
1438
1439 size = sizeof(usagecount);
1440 RegGetValueA(hkeydriver, NULL, "UsageCount", RRF_RT_DWORD, &type, &usagecount, &size);
1441 TRACE("Usage count %d\n", usagecount);
1442 count = usagecount - 1;
1443 if (count)
1444 {
1445 if (RegSetValueExA(hkeydriver, "UsageCount", 0, REG_DWORD, (BYTE*)&count, sizeof(count)) != ERROR_SUCCESS)
1446 ERR("Failed to write registry UsageCount key\n");
1447 }
1448
1449 RegCloseKey(hkeydriver);
1450 }
1451
1452 if (usagecount)
1453 usagecount--;
1454
1455 if (!usagecount)
1456 {
1457 if(RegDeleteKeyW(hkey, translator) != ERROR_SUCCESS)
1458 {
1459 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
1460 WARN("Failed to delete registry key: %s\n", debugstr_w(translator));
1461 ret = FALSE;
1462 }
1463
1464 if (ret && RegOpenKeyW(hkey, odbctranslators, &hkeydriver) == ERROR_SUCCESS)
1465 {
1466 if(RegDeleteValueW(hkeydriver, translator) != ERROR_SUCCESS)
1467 {
1468 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
1469 WARN("Failed to delete registry key: %s\n", debugstr_w(translator));
1470 ret = FALSE;
1471 }
1472
1473 RegCloseKey(hkeydriver);
1474 }
1475 }
1476
1477 RegCloseKey(hkey);
1478 }
1479
1480 if (ret && usage_count)
1481 *usage_count = usagecount;
1482
1483 return ret;
1484 }
1485
SQLRemoveTranslator(LPCSTR lpszTranslator,LPDWORD lpdwUsageCount)1486 BOOL WINAPI SQLRemoveTranslator(LPCSTR lpszTranslator, LPDWORD lpdwUsageCount)
1487 {
1488 WCHAR *translator;
1489 BOOL ret;
1490
1491 clear_errors();
1492 TRACE("%s %p\n", debugstr_a(lpszTranslator), lpdwUsageCount);
1493
1494 translator = SQLInstall_strdup(lpszTranslator);
1495 ret = SQLRemoveTranslatorW(translator, lpdwUsageCount);
1496
1497 HeapFree(GetProcessHeap(), 0, translator);
1498 return ret;
1499 }
1500
SQLSetConfigMode(UWORD wConfigMode)1501 BOOL WINAPI SQLSetConfigMode(UWORD wConfigMode)
1502 {
1503 clear_errors();
1504 TRACE("%u\n", wConfigMode);
1505
1506 if (wConfigMode > ODBC_SYSTEM_DSN)
1507 {
1508 push_error(ODBC_ERROR_INVALID_PARAM_SEQUENCE, odbc_error_invalid_param_sequence);
1509 return FALSE;
1510 }
1511 else
1512 {
1513 config_mode = wConfigMode;
1514 return TRUE;
1515 }
1516 }
1517
SQLValidDSNW(LPCWSTR lpszDSN)1518 BOOL WINAPI SQLValidDSNW(LPCWSTR lpszDSN)
1519 {
1520 static const WCHAR invalid[] = {'[',']','{','}','(',')',',',';','?','*','=','!','@','\\',0};
1521 clear_errors();
1522 TRACE("%s\n", debugstr_w(lpszDSN));
1523
1524 if(lstrlenW(lpszDSN) > SQL_MAX_DSN_LENGTH || wcspbrk(lpszDSN, invalid) != NULL)
1525 {
1526 return FALSE;
1527 }
1528
1529 return TRUE;
1530 }
1531
SQLValidDSN(LPCSTR lpszDSN)1532 BOOL WINAPI SQLValidDSN(LPCSTR lpszDSN)
1533 {
1534 static const char *invalid = "[]{}(),;?*=!@\\";
1535 clear_errors();
1536 TRACE("%s\n", debugstr_a(lpszDSN));
1537
1538 if(strlen(lpszDSN) > SQL_MAX_DSN_LENGTH || strpbrk(lpszDSN, invalid) != NULL)
1539 {
1540 return FALSE;
1541 }
1542
1543 return TRUE;
1544 }
1545
SQLWriteDSNToIniW(LPCWSTR lpszDSN,LPCWSTR lpszDriver)1546 BOOL WINAPI SQLWriteDSNToIniW(LPCWSTR lpszDSN, LPCWSTR lpszDriver)
1547 {
1548 clear_errors();
1549 FIXME("%s %s\n", debugstr_w(lpszDSN), debugstr_w(lpszDriver));
1550 return TRUE;
1551 }
1552
SQLWriteDSNToIni(LPCSTR lpszDSN,LPCSTR lpszDriver)1553 BOOL WINAPI SQLWriteDSNToIni(LPCSTR lpszDSN, LPCSTR lpszDriver)
1554 {
1555 clear_errors();
1556 FIXME("%s %s\n", debugstr_a(lpszDSN), debugstr_a(lpszDriver));
1557 return TRUE;
1558 }
1559
SQLWriteFileDSNW(LPCWSTR lpszFileName,LPCWSTR lpszAppName,LPCWSTR lpszKeyName,LPCWSTR lpszString)1560 BOOL WINAPI SQLWriteFileDSNW(LPCWSTR lpszFileName, LPCWSTR lpszAppName,
1561 LPCWSTR lpszKeyName, LPCWSTR lpszString)
1562 {
1563 clear_errors();
1564 FIXME("%s %s %s %s\n", debugstr_w(lpszFileName), debugstr_w(lpszAppName),
1565 debugstr_w(lpszKeyName), debugstr_w(lpszString));
1566 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1567 return FALSE;
1568 }
1569
SQLWriteFileDSN(LPCSTR lpszFileName,LPCSTR lpszAppName,LPCSTR lpszKeyName,LPCSTR lpszString)1570 BOOL WINAPI SQLWriteFileDSN(LPCSTR lpszFileName, LPCSTR lpszAppName,
1571 LPCSTR lpszKeyName, LPCSTR lpszString)
1572 {
1573 clear_errors();
1574 FIXME("%s %s %s %s\n", debugstr_a(lpszFileName), debugstr_a(lpszAppName),
1575 debugstr_a(lpszKeyName), debugstr_a(lpszString));
1576 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1577 return FALSE;
1578 }
1579
SQLWritePrivateProfileStringW(LPCWSTR lpszSection,LPCWSTR lpszEntry,LPCWSTR lpszString,LPCWSTR lpszFilename)1580 BOOL WINAPI SQLWritePrivateProfileStringW(LPCWSTR lpszSection, LPCWSTR lpszEntry,
1581 LPCWSTR lpszString, LPCWSTR lpszFilename)
1582 {
1583 static const WCHAR empty[] = {0};
1584 LONG ret;
1585 HKEY hkey;
1586
1587 clear_errors();
1588 TRACE("%s %s %s %s\n", debugstr_w(lpszSection), debugstr_w(lpszEntry),
1589 debugstr_w(lpszString), debugstr_w(lpszFilename));
1590
1591 if(!lpszFilename || !*lpszFilename)
1592 {
1593 push_error(ODBC_ERROR_INVALID_STR, odbc_error_invalid_param_string);
1594 return FALSE;
1595 }
1596
1597 if ((ret = RegCreateKeyW(HKEY_CURRENT_USER, odbcW, &hkey)) == ERROR_SUCCESS)
1598 {
1599 HKEY hkeyfilename;
1600
1601 if ((ret = RegCreateKeyW(hkey, lpszFilename, &hkeyfilename)) == ERROR_SUCCESS)
1602 {
1603 HKEY hkey_section;
1604
1605 if ((ret = RegCreateKeyW(hkeyfilename, lpszSection, &hkey_section)) == ERROR_SUCCESS)
1606 {
1607 if(lpszString)
1608 ret = RegSetValueExW(hkey_section, lpszEntry, 0, REG_SZ, (BYTE*)lpszString, (lstrlenW(lpszString)+1)*sizeof(WCHAR));
1609 else
1610 ret = RegSetValueExW(hkey_section, lpszEntry, 0, REG_SZ, (BYTE*)empty, sizeof(empty));
1611 RegCloseKey(hkey_section);
1612 }
1613
1614 RegCloseKey(hkeyfilename);
1615 }
1616
1617 RegCloseKey(hkey);
1618 }
1619
1620 return ret == ERROR_SUCCESS;
1621 }
1622
SQLWritePrivateProfileString(LPCSTR lpszSection,LPCSTR lpszEntry,LPCSTR lpszString,LPCSTR lpszFilename)1623 BOOL WINAPI SQLWritePrivateProfileString(LPCSTR lpszSection, LPCSTR lpszEntry,
1624 LPCSTR lpszString, LPCSTR lpszFilename)
1625 {
1626 BOOL ret;
1627 WCHAR *sect, *entry, *string, *file;
1628 clear_errors();
1629 TRACE("%s %s %s %s\n", lpszSection, lpszEntry, lpszString, lpszFilename);
1630
1631 sect = heap_strdupAtoW(lpszSection);
1632 entry = heap_strdupAtoW(lpszEntry);
1633 string = heap_strdupAtoW(lpszString);
1634 file = heap_strdupAtoW(lpszFilename);
1635
1636 ret = SQLWritePrivateProfileStringW(sect, entry, string, file);
1637
1638 heap_free(sect);
1639 heap_free(entry);
1640 heap_free(string);
1641 heap_free(file);
1642
1643 return ret;
1644 }
1645