makefiles: Explicitly create destination dirs when installing symlinks.
[wine/zf.git] / dlls / odbccp32 / odbccp32.c
blobc842872fa6e80d4b1f5a72927cddb9903a825433
1 /*
2 * Implementation of the ODBC driver installer
4 * Copyright 2005 Mike McCormack for CodeWeavers
5 * Copyright 2005 Hans Leidekker
6 * Copyright 2007 Bill Medland
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.
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.
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
23 #include <assert.h>
24 #include <stdarg.h>
26 #define COBJMACROS
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "winnls.h"
32 #include "sqlext.h"
33 #include "wine/debug.h"
34 #include "wine/heap.h"
36 #include "odbcinst.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(odbc);
40 /* Registry key names */
41 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};
42 static const WCHAR odbcW[] = {'S','o','f','t','w','a','r','e','\\','O','D','B','C',0};
43 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};
44 static const WCHAR odbcdrivers[] = {'O','D','B','C',' ','D','r','i','v','e','r','s',0};
45 static const WCHAR odbctranslators[] = {'O','D','B','C',' ','T','r','a','n','s','l','a','t','o','r','s',0};
47 /* This config mode is known to be process-wide.
48 * MSDN documentation suggests that the value is hidden somewhere in the registry but I haven't found it yet.
49 * Although both the registry and the ODBC.ini files appear to be maintained together they are not maintained automatically through the registry's IniFileMapping.
51 static UWORD config_mode = ODBC_BOTH_DSN;
53 /* MSDN documentation suggests that the error subsystem handles errors 1 to 8
54 * only and experimentation (Windows 2000) shows that the errors are process-
55 * wide so go for the simple solution; static arrays.
57 static int num_errors;
58 static int error_code[8];
59 static const WCHAR *error_msg[8];
60 static const WCHAR odbc_error_general_err[] = {'G','e','n','e','r','a','l',' ','e','r','r','o','r',0};
61 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};
62 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};
63 static const WCHAR odbc_error_out_of_mem[] = {'O','u','t',' ','o','f',' ','m','e','m','o','r','y',0};
64 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};
65 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};
66 static const WCHAR odbc_error_invalid_dsn[] = {'I','n','v','a','l','i','d',' ','D','S','N',0};
67 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};
68 static const WCHAR odbc_error_request_failed[] = {'R','e','q','u','e','s','t',' ','F','a','i','l','e','d',0};
69 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};
71 static BOOL (WINAPI *pConfigDSN)(HWND hwnd, WORD request, const char *driver, const char *attr);
72 static BOOL (WINAPI *pConfigDSNW)(HWND hwnd, WORD request, const WCHAR *driver, const WCHAR *attr);
74 /* Push an error onto the error stack, taking care of ranges etc. */
75 static void push_error(int code, LPCWSTR msg)
77 if (num_errors < ARRAY_SIZE(error_code))
79 error_code[num_errors] = code;
80 error_msg[num_errors] = msg;
81 num_errors++;
85 /* Clear the error stack */
86 static void clear_errors(void)
88 num_errors = 0;
91 static inline WCHAR *heap_strdupAtoW(const char *str)
93 LPWSTR ret = NULL;
95 if(str) {
96 DWORD len;
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);
104 return ret;
108 BOOL WINAPI ODBCCPlApplet( LONG i, LONG j, LONG * p1, LONG * p2)
110 clear_errors();
111 FIXME( "( %d %d %p %p) : stub!\n", i, j, p1, p2);
112 return FALSE;
115 static LPWSTR SQLInstall_strdup_multi(LPCSTR str)
117 LPCSTR p;
118 LPWSTR ret = NULL;
119 DWORD len;
121 if (!str)
122 return ret;
124 for (p = str; *p; p += lstrlenA(p) + 1)
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;
132 return ret;
135 static LPWSTR SQLInstall_strdup(LPCSTR str)
137 DWORD len;
138 LPWSTR ret = NULL;
140 if (!str)
141 return ret;
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 );
147 return ret;
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.
173 static BOOL SQLInstall_narrow(int mode, LPSTR buffer, LPCWSTR str, WORD str_length, WORD buffer_length, WORD *returned_length)
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)
183 if (len > buffer_length)
185 pbuf = HeapAlloc(GetProcessHeap(), 0, len);
187 else
189 pbuf = buffer;
191 len = WideCharToMultiByte(CP_ACP, 0, str, str_length, pbuf, len, NULL, NULL);
192 if (len > 0)
194 if (pbuf != buffer)
196 if (buffer_length > (mode - 1))
198 memcpy (buffer, pbuf, buffer_length-mode);
199 *(buffer+buffer_length-mode) = '\0';
201 *(buffer+buffer_length-1) = '\0';
203 if (returned_length)
205 *returned_length = pbuf == buffer ? len : buffer_length;
207 success = TRUE;
209 else
211 ERR("transferring wide to narrow\n");
213 if (pbuf != buffer)
215 HeapFree(GetProcessHeap(), 0, pbuf);
218 else
220 ERR("measuring wide to narrow\n");
222 return success;
225 static HMODULE load_config_driver(const WCHAR *driver)
227 static WCHAR reg_driver[] = {'d','r','i','v','e','r',0};
228 long ret;
229 HMODULE hmod;
230 WCHAR *filename = NULL;
231 DWORD size = 0, type;
232 HKEY hkey;
234 if ((ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey)) == ERROR_SUCCESS)
236 HKEY hkeydriver;
238 if ((ret = RegOpenKeyW(hkey, driver, &hkeydriver)) == ERROR_SUCCESS)
240 ret = RegGetValueW(hkeydriver, NULL, reg_driver, RRF_RT_REG_SZ, &type, NULL, &size);
241 if(ret != ERROR_SUCCESS || type != REG_SZ)
243 RegCloseKey(hkeydriver);
244 RegCloseKey(hkey);
245 push_error(ODBC_ERROR_INVALID_DSN, odbc_error_invalid_dsn);
247 return NULL;
250 filename = HeapAlloc(GetProcessHeap(), 0, size);
251 if(!filename)
253 RegCloseKey(hkeydriver);
254 RegCloseKey(hkey);
255 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
257 return NULL;
259 ret = RegGetValueW(hkeydriver, NULL, reg_driver, RRF_RT_REG_SZ, &type, filename, &size);
261 RegCloseKey(hkeydriver);
264 RegCloseKey(hkey);
267 if(ret != ERROR_SUCCESS)
269 HeapFree(GetProcessHeap(), 0, filename);
270 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
271 return NULL;
274 hmod = LoadLibraryW(filename);
275 HeapFree(GetProcessHeap(), 0, filename);
277 if(!hmod)
278 push_error(ODBC_ERROR_LOAD_LIB_FAILED, odbc_error_load_lib_failed);
280 return hmod;
283 static BOOL write_config_value(const WCHAR *driver, const WCHAR *args)
285 long ret;
286 HKEY hkey, hkeydriver;
287 WCHAR *name = NULL;
289 if(!args)
290 return FALSE;
292 if((ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey)) == ERROR_SUCCESS)
294 if((ret = RegOpenKeyW(hkey, driver, &hkeydriver)) == ERROR_SUCCESS)
296 WCHAR *divider, *value;
298 name = heap_alloc( (lstrlenW(args) + 1) * sizeof(WCHAR));
299 if(!name)
301 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
302 goto fail;
304 lstrcpyW(name, args);
306 divider = wcschr(name,'=');
307 if(!divider)
309 push_error(ODBC_ERROR_INVALID_KEYWORD_VALUE, odbc_error_invalid_keyword);
310 goto fail;
313 value = divider + 1;
314 *divider = '\0';
316 TRACE("Write pair: %s = %s\n", debugstr_w(name), debugstr_w(value));
317 if(RegSetValueExW(hkeydriver, name, 0, REG_SZ, (BYTE*)value,
318 (lstrlenW(value)+1) * sizeof(WCHAR)) != ERROR_SUCCESS)
319 ERR("Failed to write registry installed key\n");
320 heap_free(name);
322 RegCloseKey(hkeydriver);
325 RegCloseKey(hkey);
328 if(ret != ERROR_SUCCESS)
329 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
331 return ret == ERROR_SUCCESS;
333 fail:
334 RegCloseKey(hkeydriver);
335 RegCloseKey(hkey);
336 heap_free(name);
338 return FALSE;
341 BOOL WINAPI SQLConfigDataSourceW(HWND hwnd, WORD request, LPCWSTR driver, LPCWSTR attributes)
343 HMODULE mod;
344 BOOL ret = FALSE;
346 TRACE("%p, %d, %s, %s\n", hwnd, request, debugstr_w(driver), debugstr_w(attributes));
347 if (TRACE_ON(odbc))
349 const WCHAR *p;
350 for (p = attributes; *p; p += lstrlenW(p) + 1)
351 TRACE("%s\n", debugstr_w(p));
354 clear_errors();
356 mod = load_config_driver(driver);
357 if (!mod)
358 return FALSE;
360 pConfigDSNW = (void*)GetProcAddress(mod, "ConfigDSNW");
361 if(pConfigDSNW)
362 ret = pConfigDSNW(hwnd, request, driver, attributes);
363 else
364 ERR("Failed to find ConfigDSNW\n");
366 if (!ret)
367 push_error(ODBC_ERROR_REQUEST_FAILED, odbc_error_request_failed);
369 FreeLibrary(mod);
371 return ret;
374 BOOL WINAPI SQLConfigDataSource(HWND hwnd, WORD request, LPCSTR driver, LPCSTR attributes)
376 HMODULE mod;
377 BOOL ret = FALSE;
378 WCHAR *driverW;
380 TRACE("%p, %d, %s, %s\n", hwnd, request, debugstr_a(driver), debugstr_a(attributes));
382 if (TRACE_ON(odbc))
384 const char *p;
385 for (p = attributes; *p; p += lstrlenA(p) + 1)
386 TRACE("%s\n", debugstr_a(p));
389 clear_errors();
391 driverW = heap_strdupAtoW(driver);
392 if (!driverW)
394 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
395 return FALSE;
398 mod = load_config_driver(driverW);
399 if (!mod)
401 heap_free(driverW);
402 return FALSE;
405 pConfigDSN = (void*)GetProcAddress(mod, "ConfigDSN");
406 if (pConfigDSN)
408 TRACE("Calling ConfigDSN\n");
409 ret = pConfigDSN(hwnd, request, driver, attributes);
411 else
413 pConfigDSNW = (void*)GetProcAddress(mod, "ConfigDSNW");
414 if (pConfigDSNW)
416 WCHAR *attr = NULL;
417 TRACE("Calling ConfigDSNW\n");
419 attr = SQLInstall_strdup_multi(attributes);
420 if(attr)
421 ret = pConfigDSNW(hwnd, request, driverW, attr);
422 heap_free(attr);
426 if (!ret)
427 push_error(ODBC_ERROR_REQUEST_FAILED, odbc_error_request_failed);
429 heap_free(driverW);
430 FreeLibrary(mod);
432 return ret;
435 BOOL WINAPI SQLConfigDriverW(HWND hwnd, WORD request, LPCWSTR driver,
436 LPCWSTR args, LPWSTR msg, WORD msgmax, WORD *msgout)
438 BOOL (WINAPI *pConfigDriverW)(HWND hwnd, WORD request, const WCHAR *driver, const WCHAR *args, const WCHAR *msg, WORD msgmax, WORD *msgout);
439 HMODULE hmod;
440 BOOL funcret = FALSE;
442 clear_errors();
443 TRACE("(%p %d %s %s %p %d %p)\n", hwnd, request, debugstr_w(driver),
444 debugstr_w(args), msg, msgmax, msgout);
446 if(request == ODBC_CONFIG_DRIVER)
448 return write_config_value(driver, args);
451 hmod = load_config_driver(driver);
452 if(!hmod)
453 return FALSE;
455 pConfigDriverW = (void*)GetProcAddress(hmod, "ConfigDriverW");
456 if(pConfigDriverW)
457 funcret = pConfigDriverW(hwnd, request, driver, args, msg, msgmax, msgout);
459 if(!funcret)
460 push_error(ODBC_ERROR_REQUEST_FAILED, odbc_error_request_failed);
462 FreeLibrary(hmod);
464 return funcret;
467 BOOL WINAPI SQLConfigDriver(HWND hwnd, WORD request, LPCSTR driver,
468 LPCSTR args, LPSTR msg, WORD msgmax, WORD *msgout)
470 BOOL (WINAPI *pConfigDriverA)(HWND hwnd, WORD request, const char *driver, const char *args, const char *msg, WORD msgmax, WORD *msgout);
471 HMODULE hmod;
472 WCHAR *driverW;
473 BOOL funcret = FALSE;
475 clear_errors();
476 TRACE("(%p %d %s %s %p %d %p)\n", hwnd, request, debugstr_a(driver),
477 debugstr_a(args), msg, msgmax, msgout);
479 driverW = heap_strdupAtoW(driver);
480 if(!driverW)
482 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
483 return FALSE;
485 if(request == ODBC_CONFIG_DRIVER)
487 BOOL ret = FALSE;
488 WCHAR *argsW = heap_strdupAtoW(args);
489 if(argsW)
491 ret = write_config_value(driverW, argsW);
492 HeapFree(GetProcessHeap(), 0, argsW);
494 else
496 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
499 HeapFree(GetProcessHeap(), 0, driverW);
501 return ret;
504 hmod = load_config_driver(driverW);
505 HeapFree(GetProcessHeap(), 0, driverW);
506 if(!hmod)
507 return FALSE;
509 pConfigDriverA = (void*)GetProcAddress(hmod, "ConfigDriver");
510 if(pConfigDriverA)
511 funcret = pConfigDriverA(hwnd, request, driver, args, msg, msgmax, msgout);
513 if(!funcret)
514 push_error(ODBC_ERROR_REQUEST_FAILED, odbc_error_request_failed);
516 FreeLibrary(hmod);
518 return funcret;
521 BOOL WINAPI SQLCreateDataSourceW(HWND hwnd, LPCWSTR lpszDS)
523 clear_errors();
524 FIXME("%p %s\n", hwnd, debugstr_w(lpszDS));
525 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
526 return FALSE;
529 BOOL WINAPI SQLCreateDataSource(HWND hwnd, LPCSTR lpszDS)
531 clear_errors();
532 FIXME("%p %s\n", hwnd, debugstr_a(lpszDS));
533 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
534 return FALSE;
537 BOOL WINAPI SQLGetAvailableDriversW(LPCWSTR lpszInfFile, LPWSTR lpszBuf,
538 WORD cbBufMax, WORD *pcbBufOut)
540 clear_errors();
541 FIXME("%s %p %d %p\n", debugstr_w(lpszInfFile), lpszBuf, cbBufMax, pcbBufOut);
542 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
543 return FALSE;
546 BOOL WINAPI SQLGetAvailableDrivers(LPCSTR lpszInfFile, LPSTR lpszBuf,
547 WORD cbBufMax, WORD *pcbBufOut)
549 clear_errors();
550 FIXME("%s %p %d %p\n", debugstr_a(lpszInfFile), lpszBuf, cbBufMax, pcbBufOut);
551 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
552 return FALSE;
555 BOOL WINAPI SQLGetConfigMode(UWORD *pwConfigMode)
557 clear_errors();
558 TRACE("%p\n", pwConfigMode);
559 if (pwConfigMode)
560 *pwConfigMode = config_mode;
561 return TRUE;
564 BOOL WINAPI SQLGetInstalledDriversW(WCHAR *buf, WORD size, WORD *sizeout)
566 WORD written = 0;
567 DWORD index = 0;
568 BOOL ret = TRUE;
569 DWORD valuelen;
570 WCHAR *value;
571 HKEY drivers;
572 DWORD len;
573 LONG res;
575 clear_errors();
577 TRACE("%p %d %p\n", buf, size, sizeout);
579 if (!buf || !size)
581 push_error(ODBC_ERROR_INVALID_BUFF_LEN, odbc_error_invalid_buff_len);
582 return FALSE;
585 res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, drivers_key, 0, KEY_QUERY_VALUE, &drivers);
586 if (res)
588 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
589 return FALSE;
592 valuelen = 256;
593 value = heap_alloc(valuelen * sizeof(WCHAR));
595 size--;
597 while (1)
599 len = valuelen;
600 res = RegEnumValueW(drivers, index, value, &len, NULL, NULL, NULL, NULL);
601 while (res == ERROR_MORE_DATA)
603 value = heap_realloc(value, ++len * sizeof(WCHAR));
604 res = RegEnumValueW(drivers, index, value, &len, NULL, NULL, NULL, NULL);
606 if (res == ERROR_SUCCESS)
608 lstrcpynW(buf + written, value, size - written);
609 written += min(len + 1, size - written);
611 else if (res == ERROR_NO_MORE_ITEMS)
612 break;
613 else
615 push_error(ODBC_ERROR_GENERAL_ERR, odbc_error_general_err);
616 ret = FALSE;
617 break;
619 index++;
622 buf[written++] = 0;
624 heap_free(value);
625 RegCloseKey(drivers);
626 if (sizeout)
627 *sizeout = written;
628 return ret;
631 BOOL WINAPI SQLGetInstalledDrivers(char *buf, WORD size, WORD *sizeout)
633 WORD written;
634 WCHAR *wbuf;
635 BOOL ret;
637 TRACE("%p %d %p\n", buf, size, sizeout);
639 if (!buf || !size)
641 push_error(ODBC_ERROR_INVALID_BUFF_LEN, odbc_error_invalid_buff_len);
642 return FALSE;
645 wbuf = heap_alloc(size * sizeof(WCHAR));
646 if (!wbuf)
648 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
649 return FALSE;
652 ret = SQLGetInstalledDriversW(wbuf, size, &written);
653 if (!ret)
655 heap_free(wbuf);
656 return FALSE;
659 if (sizeout)
660 *sizeout = WideCharToMultiByte(CP_ACP, 0, wbuf, written, NULL, 0, NULL, NULL);
661 WideCharToMultiByte(CP_ACP, 0, wbuf, written, buf, size, NULL, NULL);
663 heap_free(wbuf);
664 return TRUE;
667 static HKEY get_privateprofile_sectionkey(LPCWSTR section, LPCWSTR filename)
669 HKEY hkey, hkeyfilename, hkeysection;
670 LONG ret;
672 if (RegOpenKeyW(HKEY_CURRENT_USER, odbcW, &hkey))
673 return NULL;
675 ret = RegOpenKeyW(hkey, filename, &hkeyfilename);
676 RegCloseKey(hkey);
677 if (ret)
678 return NULL;
680 ret = RegOpenKeyW(hkeyfilename, section, &hkeysection);
681 RegCloseKey(hkeyfilename);
683 return ret ? NULL : hkeysection;
686 int WINAPI SQLGetPrivateProfileStringW(LPCWSTR section, LPCWSTR entry,
687 LPCWSTR defvalue, LPWSTR buff, int buff_len, LPCWSTR filename)
689 BOOL usedefault = TRUE;
690 HKEY sectionkey;
691 LONG ret = 0;
693 TRACE("%s %s %s %p %d %s\n", debugstr_w(section), debugstr_w(entry),
694 debugstr_w(defvalue), buff, buff_len, debugstr_w(filename));
696 clear_errors();
698 if (buff_len <= 0 || !section)
699 return 0;
701 if(buff)
702 buff[0] = 0;
704 if (!defvalue || !buff)
705 return 0;
707 sectionkey = get_privateprofile_sectionkey(section, filename);
708 if (sectionkey)
710 DWORD type, size;
712 if (entry)
714 size = buff_len * sizeof(*buff);
715 if (RegGetValueW(sectionkey, NULL, entry, RRF_RT_REG_SZ, &type, buff, &size) == ERROR_SUCCESS)
717 usedefault = FALSE;
718 ret = (size / sizeof(*buff)) - 1;
721 else
723 WCHAR name[MAX_PATH];
724 DWORD index = 0;
725 DWORD namelen;
727 usedefault = FALSE;
729 memset(buff, 0, buff_len);
731 namelen = sizeof(name);
732 while (RegEnumValueW(sectionkey, index, name, &namelen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
734 if ((ret + namelen+1) > buff_len)
735 break;
737 lstrcpyW(buff+ret, name);
738 ret += namelen+1;
739 namelen = sizeof(name);
740 index++;
744 RegCloseKey(sectionkey);
746 else
747 usedefault = entry != NULL;
749 if (usedefault)
751 lstrcpynW(buff, defvalue, buff_len);
752 ret = lstrlenW(buff);
755 return ret;
758 int WINAPI SQLGetPrivateProfileString(LPCSTR section, LPCSTR entry,
759 LPCSTR defvalue, LPSTR buff, int buff_len, LPCSTR filename)
761 WCHAR *sectionW, *filenameW;
762 BOOL usedefault = TRUE;
763 HKEY sectionkey;
764 LONG ret = 0;
766 TRACE("%s %s %s %p %d %s\n", debugstr_a(section), debugstr_a(entry),
767 debugstr_a(defvalue), buff, buff_len, debugstr_a(filename));
769 clear_errors();
771 if (buff_len <= 0)
772 return 0;
774 if (buff)
775 buff[0] = 0;
777 if (!section || !defvalue || !buff)
778 return 0;
780 sectionW = heap_strdupAtoW(section);
781 filenameW = heap_strdupAtoW(filename);
783 sectionkey = get_privateprofile_sectionkey(sectionW, filenameW);
785 heap_free(sectionW);
786 heap_free(filenameW);
788 if (sectionkey)
790 DWORD type, size;
792 if (entry)
794 size = buff_len * sizeof(*buff);
795 if (RegGetValueA(sectionkey, NULL, entry, RRF_RT_REG_SZ, &type, buff, &size) == ERROR_SUCCESS)
797 usedefault = FALSE;
798 ret = (size / sizeof(*buff)) - 1;
801 else
803 char name[MAX_PATH] = {0};
804 DWORD index = 0;
805 DWORD namelen;
807 usedefault = FALSE;
809 memset(buff, 0, buff_len);
811 namelen = sizeof(name);
812 while (RegEnumValueA(sectionkey, index, name, &namelen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
814 if ((ret + namelen+1) > buff_len)
815 break;
817 lstrcpyA(buff+ret, name);
819 ret += namelen+1;
820 namelen = sizeof(name);
821 index++;
825 RegCloseKey(sectionkey);
827 else
828 usedefault = entry != NULL;
830 if (usedefault)
832 lstrcpynA(buff, defvalue, buff_len);
833 ret = strlen(buff);
836 return ret;
839 BOOL WINAPI SQLGetTranslatorW(HWND hwndParent, LPWSTR lpszName, WORD cbNameMax,
840 WORD *pcbNameOut, LPWSTR lpszPath, WORD cbPathMax,
841 WORD *pcbPathOut, DWORD *pvOption)
843 clear_errors();
844 FIXME("%p %s %d %p %p %d %p %p\n", hwndParent, debugstr_w(lpszName), cbNameMax,
845 pcbNameOut, lpszPath, cbPathMax, pcbPathOut, pvOption);
846 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
847 return FALSE;
850 BOOL WINAPI SQLGetTranslator(HWND hwndParent, LPSTR lpszName, WORD cbNameMax,
851 WORD *pcbNameOut, LPSTR lpszPath, WORD cbPathMax,
852 WORD *pcbPathOut, DWORD *pvOption)
854 clear_errors();
855 FIXME("%p %s %d %p %p %d %p %p\n", hwndParent, debugstr_a(lpszName), cbNameMax,
856 pcbNameOut, lpszPath, cbPathMax, pcbPathOut, pvOption);
857 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
858 return FALSE;
861 BOOL WINAPI SQLInstallDriverW(LPCWSTR lpszInfFile, LPCWSTR lpszDriver,
862 LPWSTR lpszPath, WORD cbPathMax, WORD * pcbPathOut)
864 DWORD usage;
866 clear_errors();
867 TRACE("%s %s %p %d %p\n", debugstr_w(lpszInfFile),
868 debugstr_w(lpszDriver), lpszPath, cbPathMax, pcbPathOut);
870 if (lpszInfFile)
871 return FALSE;
873 return SQLInstallDriverExW(lpszDriver, NULL, lpszPath, cbPathMax,
874 pcbPathOut, ODBC_INSTALL_COMPLETE, &usage);
877 BOOL WINAPI SQLInstallDriver(LPCSTR lpszInfFile, LPCSTR lpszDriver,
878 LPSTR lpszPath, WORD cbPathMax, WORD * pcbPathOut)
880 DWORD usage;
882 clear_errors();
883 TRACE("%s %s %p %d %p\n", debugstr_a(lpszInfFile),
884 debugstr_a(lpszDriver), lpszPath, cbPathMax, pcbPathOut);
886 if (lpszInfFile)
887 return FALSE;
889 return SQLInstallDriverEx(lpszDriver, NULL, lpszPath, cbPathMax,
890 pcbPathOut, ODBC_INSTALL_COMPLETE, &usage);
893 static void write_registry_values(const WCHAR *regkey, const WCHAR *driver, const WCHAR *path_in, WCHAR *path,
894 DWORD *usage_count)
896 static const WCHAR installed[] = {'I','n','s','t','a','l','l','e','d',0};
897 static const WCHAR slash[] = {'\\', 0};
898 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
899 static const WCHAR setupW[] = {'S','e','t','u','p',0};
900 static const WCHAR translator[] = {'T','r','a','n','s','l','a','t','o','r',0};
901 HKEY hkey, hkeydriver;
903 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey) == ERROR_SUCCESS)
905 if (RegCreateKeyW(hkey, regkey, &hkeydriver) == ERROR_SUCCESS)
907 if(RegSetValueExW(hkeydriver, driver, 0, REG_SZ, (BYTE*)installed, sizeof(installed)) != ERROR_SUCCESS)
908 ERR("Failed to write registry installed key\n");
910 RegCloseKey(hkeydriver);
913 if (RegCreateKeyW(hkey, driver, &hkeydriver) == ERROR_SUCCESS)
915 WCHAR entry[1024];
916 const WCHAR *p;
917 DWORD usagecount = 0;
918 DWORD type, size;
920 /* Skip name entry */
921 p = driver;
922 p += lstrlenW(p) + 1;
924 if (!path_in)
925 GetSystemDirectoryW(path, MAX_PATH);
926 else
927 lstrcpyW(path, path_in);
929 /* Store Usage */
930 size = sizeof(usagecount);
931 RegGetValueA(hkeydriver, NULL, "UsageCount", RRF_RT_DWORD, &type, &usagecount, &size);
932 TRACE("Usage count %d\n", usagecount);
934 for (; *p; p += lstrlenW(p) + 1)
936 WCHAR *divider = wcschr(p,'=');
938 if (divider)
940 WCHAR *value;
941 int len;
943 /* Write pair values to the registry. */
944 lstrcpynW(entry, p, divider - p + 1);
946 divider++;
947 TRACE("Writing pair %s,%s\n", debugstr_w(entry), debugstr_w(divider));
949 /* Driver, Setup, Translator entries use the system path unless a path is specified. */
950 if(lstrcmpiW(driverW, entry) == 0 || lstrcmpiW(setupW, entry) == 0 ||
951 lstrcmpiW(translator, entry) == 0)
953 len = lstrlenW(path) + lstrlenW(slash) + lstrlenW(divider) + 1;
954 value = heap_alloc(len * sizeof(WCHAR));
955 if(!value)
957 ERR("Out of memory\n");
958 return;
961 lstrcpyW(value, path);
962 lstrcatW(value, slash);
963 lstrcatW(value, divider);
965 else
967 len = lstrlenW(divider) + 1;
968 value = heap_alloc(len * sizeof(WCHAR));
969 lstrcpyW(value, divider);
972 if (RegSetValueExW(hkeydriver, entry, 0, REG_SZ, (BYTE*)value,
973 (lstrlenW(value)+1)*sizeof(WCHAR)) != ERROR_SUCCESS)
974 ERR("Failed to write registry data %s %s\n", debugstr_w(entry), debugstr_w(value));
975 heap_free(value);
977 else
979 ERR("No pair found. %s\n", debugstr_w(p));
980 break;
984 /* Set Usage Count */
985 usagecount++;
986 if (RegSetValueExA(hkeydriver, "UsageCount", 0, REG_DWORD, (BYTE*)&usagecount, sizeof(usagecount)) != ERROR_SUCCESS)
987 ERR("Failed to write registry UsageCount key\n");
989 if (usage_count)
990 *usage_count = usagecount;
992 RegCloseKey(hkeydriver);
995 RegCloseKey(hkey);
999 BOOL WINAPI SQLInstallDriverExW(LPCWSTR lpszDriver, LPCWSTR lpszPathIn,
1000 LPWSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
1001 WORD fRequest, LPDWORD lpdwUsageCount)
1003 UINT len;
1004 WCHAR path[MAX_PATH];
1006 clear_errors();
1007 TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszDriver),
1008 debugstr_w(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
1009 fRequest, lpdwUsageCount);
1011 write_registry_values(odbcdrivers, lpszDriver, lpszPathIn, path, lpdwUsageCount);
1013 len = lstrlenW(path);
1015 if (pcbPathOut)
1016 *pcbPathOut = len;
1018 if (lpszPathOut && cbPathOutMax > len)
1020 lstrcpyW(lpszPathOut, path);
1021 return TRUE;
1023 return FALSE;
1026 BOOL WINAPI SQLInstallDriverEx(LPCSTR lpszDriver, LPCSTR lpszPathIn,
1027 LPSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
1028 WORD fRequest, LPDWORD lpdwUsageCount)
1030 LPWSTR driver, pathin;
1031 WCHAR pathout[MAX_PATH];
1032 BOOL ret;
1033 WORD cbOut = 0;
1035 clear_errors();
1036 TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszDriver),
1037 debugstr_a(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
1038 fRequest, lpdwUsageCount);
1040 driver = SQLInstall_strdup_multi(lpszDriver);
1041 pathin = SQLInstall_strdup(lpszPathIn);
1043 ret = SQLInstallDriverExW(driver, pathin, pathout, MAX_PATH, &cbOut,
1044 fRequest, lpdwUsageCount);
1045 if (ret)
1047 int len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
1048 0, NULL, NULL);
1049 if (len)
1051 if (pcbPathOut)
1052 *pcbPathOut = len - 1;
1054 if (!lpszPathOut || cbPathOutMax < len)
1056 ret = FALSE;
1057 goto out;
1059 len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
1060 cbPathOutMax, NULL, NULL);
1064 out:
1065 HeapFree(GetProcessHeap(), 0, driver);
1066 HeapFree(GetProcessHeap(), 0, pathin);
1067 return ret;
1070 BOOL WINAPI SQLInstallDriverManagerW(LPWSTR lpszPath, WORD cbPathMax,
1071 WORD *pcbPathOut)
1073 UINT len;
1074 WCHAR path[MAX_PATH];
1076 TRACE("(%p %d %p)\n", lpszPath, cbPathMax, pcbPathOut);
1078 if (cbPathMax < MAX_PATH)
1079 return FALSE;
1081 clear_errors();
1083 len = GetSystemDirectoryW(path, MAX_PATH);
1085 if (pcbPathOut)
1086 *pcbPathOut = len;
1088 if (lpszPath && cbPathMax > len)
1090 lstrcpyW(lpszPath, path);
1091 return TRUE;
1093 return FALSE;
1096 BOOL WINAPI SQLInstallDriverManager(LPSTR lpszPath, WORD cbPathMax,
1097 WORD *pcbPathOut)
1099 BOOL ret;
1100 WORD len, cbOut = 0;
1101 WCHAR path[MAX_PATH];
1103 TRACE("(%p %d %p)\n", lpszPath, cbPathMax, pcbPathOut);
1105 if (cbPathMax < MAX_PATH)
1106 return FALSE;
1108 clear_errors();
1110 ret = SQLInstallDriverManagerW(path, MAX_PATH, &cbOut);
1111 if (ret)
1113 len = WideCharToMultiByte(CP_ACP, 0, path, -1, lpszPath, 0,
1114 NULL, NULL);
1115 if (len)
1117 if (pcbPathOut)
1118 *pcbPathOut = len - 1;
1120 if (!lpszPath || cbPathMax < len)
1121 return FALSE;
1123 len = WideCharToMultiByte(CP_ACP, 0, path, -1, lpszPath,
1124 cbPathMax, NULL, NULL);
1127 return ret;
1130 BOOL WINAPI SQLInstallODBCW(HWND hwndParent, LPCWSTR lpszInfFile,
1131 LPCWSTR lpszSrcPath, LPCWSTR lpszDrivers)
1133 clear_errors();
1134 FIXME("%p %s %s %s\n", hwndParent, debugstr_w(lpszInfFile),
1135 debugstr_w(lpszSrcPath), debugstr_w(lpszDrivers));
1136 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1137 return FALSE;
1140 BOOL WINAPI SQLInstallODBC(HWND hwndParent, LPCSTR lpszInfFile,
1141 LPCSTR lpszSrcPath, LPCSTR lpszDrivers)
1143 clear_errors();
1144 FIXME("%p %s %s %s\n", hwndParent, debugstr_a(lpszInfFile),
1145 debugstr_a(lpszSrcPath), debugstr_a(lpszDrivers));
1146 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1147 return FALSE;
1150 SQLRETURN WINAPI SQLInstallerErrorW(WORD iError, DWORD *pfErrorCode,
1151 LPWSTR lpszErrorMsg, WORD cbErrorMsgMax, WORD *pcbErrorMsg)
1153 TRACE("%d %p %p %d %p\n", iError, pfErrorCode, lpszErrorMsg,
1154 cbErrorMsgMax, pcbErrorMsg);
1156 if (iError == 0)
1158 return SQL_ERROR;
1160 else if (iError <= num_errors)
1162 BOOL truncated = FALSE;
1163 WORD len;
1164 LPCWSTR msg;
1165 iError--;
1166 if (pfErrorCode)
1167 *pfErrorCode = error_code[iError];
1168 msg = error_msg[iError];
1169 len = msg ? lstrlenW(msg) : 0;
1170 if (pcbErrorMsg)
1171 *pcbErrorMsg = len;
1172 len++;
1173 if (cbErrorMsgMax < len)
1175 len = cbErrorMsgMax;
1176 truncated = TRUE;
1178 if (lpszErrorMsg && len)
1180 if (msg)
1182 memcpy (lpszErrorMsg, msg, len * sizeof(WCHAR));
1184 else
1186 assert(len==1);
1187 *lpszErrorMsg = 0;
1190 else
1192 /* Yes. If you pass a null pointer and a large length it is not an error! */
1193 truncated = TRUE;
1196 return truncated ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
1199 /* 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 */
1200 if (pcbErrorMsg)
1201 *pcbErrorMsg = 0;
1203 if (lpszErrorMsg && cbErrorMsgMax > 0)
1204 *lpszErrorMsg = '\0';
1206 return SQL_NO_DATA;
1209 SQLRETURN WINAPI SQLInstallerError(WORD iError, DWORD *pfErrorCode,
1210 LPSTR lpszErrorMsg, WORD cbErrorMsgMax, WORD *pcbErrorMsg)
1212 SQLRETURN ret;
1213 LPWSTR wbuf;
1214 WORD cbwbuf;
1215 TRACE("%d %p %p %d %p\n", iError, pfErrorCode, lpszErrorMsg,
1216 cbErrorMsgMax, pcbErrorMsg);
1218 wbuf = 0;
1219 if (lpszErrorMsg && cbErrorMsgMax)
1221 wbuf = HeapAlloc(GetProcessHeap(), 0, cbErrorMsgMax*sizeof(WCHAR));
1222 if (!wbuf)
1223 return SQL_ERROR;
1225 ret = SQLInstallerErrorW(iError, pfErrorCode, wbuf, cbErrorMsgMax, &cbwbuf);
1226 if (wbuf)
1228 WORD cbBuf = 0;
1229 SQLInstall_narrow(1, lpszErrorMsg, wbuf, cbwbuf+1, cbErrorMsgMax, &cbBuf);
1230 HeapFree(GetProcessHeap(), 0, wbuf);
1231 if (pcbErrorMsg)
1232 *pcbErrorMsg = cbBuf-1;
1234 return ret;
1237 BOOL WINAPI SQLInstallTranslatorExW(LPCWSTR lpszTranslator, LPCWSTR lpszPathIn,
1238 LPWSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
1239 WORD fRequest, LPDWORD lpdwUsageCount)
1241 UINT len;
1242 WCHAR path[MAX_PATH];
1244 clear_errors();
1245 TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszTranslator),
1246 debugstr_w(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
1247 fRequest, lpdwUsageCount);
1249 write_registry_values(odbctranslators, lpszTranslator, lpszPathIn, path, lpdwUsageCount);
1251 len = lstrlenW(path);
1253 if (pcbPathOut)
1254 *pcbPathOut = len;
1256 if (lpszPathOut && cbPathOutMax > len)
1258 lstrcpyW(lpszPathOut, path);
1259 return TRUE;
1261 return FALSE;
1264 BOOL WINAPI SQLInstallTranslatorEx(LPCSTR lpszTranslator, LPCSTR lpszPathIn,
1265 LPSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
1266 WORD fRequest, LPDWORD lpdwUsageCount)
1268 LPCSTR p;
1269 LPWSTR translator, pathin;
1270 WCHAR pathout[MAX_PATH];
1271 BOOL ret;
1272 WORD cbOut = 0;
1274 clear_errors();
1275 TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszTranslator),
1276 debugstr_a(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
1277 fRequest, lpdwUsageCount);
1279 for (p = lpszTranslator; *p; p += lstrlenA(p) + 1)
1280 TRACE("%s\n", debugstr_a(p));
1282 translator = SQLInstall_strdup_multi(lpszTranslator);
1283 pathin = SQLInstall_strdup(lpszPathIn);
1285 ret = SQLInstallTranslatorExW(translator, pathin, pathout, MAX_PATH,
1286 &cbOut, fRequest, lpdwUsageCount);
1287 if (ret)
1289 int len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
1290 0, NULL, NULL);
1291 if (len)
1293 if (pcbPathOut)
1294 *pcbPathOut = len - 1;
1296 if (!lpszPathOut || cbPathOutMax < len)
1298 ret = FALSE;
1299 goto out;
1301 len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
1302 cbPathOutMax, NULL, NULL);
1306 out:
1307 HeapFree(GetProcessHeap(), 0, translator);
1308 HeapFree(GetProcessHeap(), 0, pathin);
1309 return ret;
1312 BOOL WINAPI SQLInstallTranslator(LPCSTR lpszInfFile, LPCSTR lpszTranslator,
1313 LPCSTR lpszPathIn, LPSTR lpszPathOut, WORD cbPathOutMax,
1314 WORD *pcbPathOut, WORD fRequest, LPDWORD lpdwUsageCount)
1316 clear_errors();
1317 TRACE("%s %s %s %p %d %p %d %p\n", debugstr_a(lpszInfFile),
1318 debugstr_a(lpszTranslator), debugstr_a(lpszPathIn), lpszPathOut,
1319 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
1321 if (lpszInfFile)
1322 return FALSE;
1324 return SQLInstallTranslatorEx(lpszTranslator, lpszPathIn, lpszPathOut,
1325 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
1328 BOOL WINAPI SQLInstallTranslatorW(LPCWSTR lpszInfFile, LPCWSTR lpszTranslator,
1329 LPCWSTR lpszPathIn, LPWSTR lpszPathOut, WORD cbPathOutMax,
1330 WORD *pcbPathOut, WORD fRequest, LPDWORD lpdwUsageCount)
1332 clear_errors();
1333 TRACE("%s %s %s %p %d %p %d %p\n", debugstr_w(lpszInfFile),
1334 debugstr_w(lpszTranslator), debugstr_w(lpszPathIn), lpszPathOut,
1335 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
1337 if (lpszInfFile)
1338 return FALSE;
1340 return SQLInstallTranslatorExW(lpszTranslator, lpszPathIn, lpszPathOut,
1341 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
1344 BOOL WINAPI SQLManageDataSources(HWND hwnd)
1346 clear_errors();
1347 FIXME("%p\n", hwnd);
1348 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1349 return FALSE;
1352 SQLRETURN WINAPI SQLPostInstallerErrorW(DWORD fErrorCode, LPCWSTR szErrorMsg)
1354 FIXME("%u %s\n", fErrorCode, debugstr_w(szErrorMsg));
1355 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1356 return FALSE;
1359 SQLRETURN WINAPI SQLPostInstallerError(DWORD fErrorCode, LPCSTR szErrorMsg)
1361 FIXME("%u %s\n", fErrorCode, debugstr_a(szErrorMsg));
1362 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1363 return FALSE;
1366 BOOL WINAPI SQLReadFileDSNW(LPCWSTR lpszFileName, LPCWSTR lpszAppName,
1367 LPCWSTR lpszKeyName, LPWSTR lpszString, WORD cbString,
1368 WORD *pcbString)
1370 clear_errors();
1371 FIXME("%s %s %s %s %d %p\n", debugstr_w(lpszFileName), debugstr_w(lpszAppName),
1372 debugstr_w(lpszKeyName), debugstr_w(lpszString), cbString, pcbString);
1373 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1374 return FALSE;
1377 BOOL WINAPI SQLReadFileDSN(LPCSTR lpszFileName, LPCSTR lpszAppName,
1378 LPCSTR lpszKeyName, LPSTR lpszString, WORD cbString,
1379 WORD *pcbString)
1381 clear_errors();
1382 FIXME("%s %s %s %s %d %p\n", debugstr_a(lpszFileName), debugstr_a(lpszAppName),
1383 debugstr_a(lpszKeyName), debugstr_a(lpszString), cbString, pcbString);
1384 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1385 return FALSE;
1388 BOOL WINAPI SQLRemoveDefaultDataSource(void)
1390 clear_errors();
1391 FIXME("\n");
1392 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1393 return FALSE;
1396 BOOL WINAPI SQLRemoveDriverW(LPCWSTR drivername, BOOL remove_dsn, LPDWORD usage_count)
1398 HKEY hkey;
1399 DWORD usagecount = 1;
1401 clear_errors();
1402 TRACE("%s %d %p\n", debugstr_w(drivername), remove_dsn, usage_count);
1404 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey) == ERROR_SUCCESS)
1406 HKEY hkeydriver;
1408 if (RegOpenKeyW(hkey, drivername, &hkeydriver) == ERROR_SUCCESS)
1410 DWORD size, type;
1411 DWORD count;
1413 size = sizeof(usagecount);
1414 RegGetValueA(hkeydriver, NULL, "UsageCount", RRF_RT_DWORD, &type, &usagecount, &size);
1415 TRACE("Usage count %d\n", usagecount);
1416 count = usagecount - 1;
1417 if (count)
1419 if (RegSetValueExA(hkeydriver, "UsageCount", 0, REG_DWORD, (BYTE*)&count, sizeof(count)) != ERROR_SUCCESS)
1420 ERR("Failed to write registry UsageCount key\n");
1423 RegCloseKey(hkeydriver);
1426 if (usagecount)
1427 usagecount--;
1429 if (!usagecount)
1431 if (RegDeleteKeyW(hkey, drivername) != ERROR_SUCCESS)
1432 ERR("Failed to delete registry key: %s\n", debugstr_w(drivername));
1434 if (RegOpenKeyW(hkey, odbcdrivers, &hkeydriver) == ERROR_SUCCESS)
1436 if(RegDeleteValueW(hkeydriver, drivername) != ERROR_SUCCESS)
1437 ERR("Failed to delete registry value: %s\n", debugstr_w(drivername));
1438 RegCloseKey(hkeydriver);
1442 RegCloseKey(hkey);
1445 if (usage_count)
1446 *usage_count = usagecount;
1448 return TRUE;
1451 BOOL WINAPI SQLRemoveDriver(LPCSTR lpszDriver, BOOL fRemoveDSN,
1452 LPDWORD lpdwUsageCount)
1454 WCHAR *driver;
1455 BOOL ret;
1457 clear_errors();
1458 TRACE("%s %d %p\n", debugstr_a(lpszDriver), fRemoveDSN, lpdwUsageCount);
1460 driver = SQLInstall_strdup(lpszDriver);
1462 ret = SQLRemoveDriverW(driver, fRemoveDSN, lpdwUsageCount);
1464 HeapFree(GetProcessHeap(), 0, driver);
1465 return ret;
1468 BOOL WINAPI SQLRemoveDriverManager(LPDWORD pdwUsageCount)
1470 clear_errors();
1471 FIXME("%p\n", pdwUsageCount);
1472 if (pdwUsageCount) *pdwUsageCount = 1;
1473 return TRUE;
1476 BOOL WINAPI SQLRemoveDSNFromIniW(LPCWSTR lpszDSN)
1478 clear_errors();
1479 FIXME("%s\n", debugstr_w(lpszDSN));
1480 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1481 return FALSE;
1484 BOOL WINAPI SQLRemoveDSNFromIni(LPCSTR lpszDSN)
1486 clear_errors();
1487 FIXME("%s\n", debugstr_a(lpszDSN));
1488 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1489 return FALSE;
1492 BOOL WINAPI SQLRemoveTranslatorW(const WCHAR *translator, DWORD *usage_count)
1494 HKEY hkey;
1495 DWORD usagecount = 1;
1496 BOOL ret = TRUE;
1498 clear_errors();
1499 TRACE("%s %p\n", debugstr_w(translator), usage_count);
1501 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey) == ERROR_SUCCESS)
1503 HKEY hkeydriver;
1505 if (RegOpenKeyW(hkey, translator, &hkeydriver) == ERROR_SUCCESS)
1507 DWORD size, type;
1508 DWORD count;
1510 size = sizeof(usagecount);
1511 RegGetValueA(hkeydriver, NULL, "UsageCount", RRF_RT_DWORD, &type, &usagecount, &size);
1512 TRACE("Usage count %d\n", usagecount);
1513 count = usagecount - 1;
1514 if (count)
1516 if (RegSetValueExA(hkeydriver, "UsageCount", 0, REG_DWORD, (BYTE*)&count, sizeof(count)) != ERROR_SUCCESS)
1517 ERR("Failed to write registry UsageCount key\n");
1520 RegCloseKey(hkeydriver);
1523 if (usagecount)
1524 usagecount--;
1526 if (!usagecount)
1528 if(RegDeleteKeyW(hkey, translator) != ERROR_SUCCESS)
1530 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
1531 WARN("Failed to delete registry key: %s\n", debugstr_w(translator));
1532 ret = FALSE;
1535 if (ret && RegOpenKeyW(hkey, odbctranslators, &hkeydriver) == ERROR_SUCCESS)
1537 if(RegDeleteValueW(hkeydriver, translator) != ERROR_SUCCESS)
1539 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
1540 WARN("Failed to delete registry key: %s\n", debugstr_w(translator));
1541 ret = FALSE;
1544 RegCloseKey(hkeydriver);
1548 RegCloseKey(hkey);
1551 if (ret && usage_count)
1552 *usage_count = usagecount;
1554 return ret;
1557 BOOL WINAPI SQLRemoveTranslator(LPCSTR lpszTranslator, LPDWORD lpdwUsageCount)
1559 WCHAR *translator;
1560 BOOL ret;
1562 clear_errors();
1563 TRACE("%s %p\n", debugstr_a(lpszTranslator), lpdwUsageCount);
1565 translator = SQLInstall_strdup(lpszTranslator);
1566 ret = SQLRemoveTranslatorW(translator, lpdwUsageCount);
1568 HeapFree(GetProcessHeap(), 0, translator);
1569 return ret;
1572 BOOL WINAPI SQLSetConfigMode(UWORD wConfigMode)
1574 clear_errors();
1575 TRACE("%u\n", wConfigMode);
1577 if (wConfigMode > ODBC_SYSTEM_DSN)
1579 push_error(ODBC_ERROR_INVALID_PARAM_SEQUENCE, odbc_error_invalid_param_sequence);
1580 return FALSE;
1582 else
1584 config_mode = wConfigMode;
1585 return TRUE;
1589 BOOL WINAPI SQLValidDSNW(LPCWSTR lpszDSN)
1591 static const WCHAR invalid[] = {'[',']','{','}','(',')',',',';','?','*','=','!','@','\\',0};
1592 clear_errors();
1593 TRACE("%s\n", debugstr_w(lpszDSN));
1595 if(lstrlenW(lpszDSN) > SQL_MAX_DSN_LENGTH || wcspbrk(lpszDSN, invalid) != NULL)
1597 return FALSE;
1600 return TRUE;
1603 BOOL WINAPI SQLValidDSN(LPCSTR lpszDSN)
1605 static const char *invalid = "[]{}(),;?*=!@\\";
1606 clear_errors();
1607 TRACE("%s\n", debugstr_a(lpszDSN));
1609 if(strlen(lpszDSN) > SQL_MAX_DSN_LENGTH || strpbrk(lpszDSN, invalid) != NULL)
1611 return FALSE;
1614 return TRUE;
1617 BOOL WINAPI SQLWriteDSNToIniW(LPCWSTR lpszDSN, LPCWSTR lpszDriver)
1619 clear_errors();
1620 FIXME("%s %s\n", debugstr_w(lpszDSN), debugstr_w(lpszDriver));
1621 return TRUE;
1624 BOOL WINAPI SQLWriteDSNToIni(LPCSTR lpszDSN, LPCSTR lpszDriver)
1626 clear_errors();
1627 FIXME("%s %s\n", debugstr_a(lpszDSN), debugstr_a(lpszDriver));
1628 return TRUE;
1631 BOOL WINAPI SQLWriteFileDSNW(LPCWSTR lpszFileName, LPCWSTR lpszAppName,
1632 LPCWSTR lpszKeyName, LPCWSTR lpszString)
1634 clear_errors();
1635 FIXME("%s %s %s %s\n", debugstr_w(lpszFileName), debugstr_w(lpszAppName),
1636 debugstr_w(lpszKeyName), debugstr_w(lpszString));
1637 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1638 return FALSE;
1641 BOOL WINAPI SQLWriteFileDSN(LPCSTR lpszFileName, LPCSTR lpszAppName,
1642 LPCSTR lpszKeyName, LPCSTR lpszString)
1644 clear_errors();
1645 FIXME("%s %s %s %s\n", debugstr_a(lpszFileName), debugstr_a(lpszAppName),
1646 debugstr_a(lpszKeyName), debugstr_a(lpszString));
1647 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1648 return FALSE;
1651 BOOL WINAPI SQLWritePrivateProfileStringW(LPCWSTR lpszSection, LPCWSTR lpszEntry,
1652 LPCWSTR lpszString, LPCWSTR lpszFilename)
1654 static const WCHAR empty[] = {0};
1655 LONG ret;
1656 HKEY hkey;
1658 clear_errors();
1659 TRACE("%s %s %s %s\n", debugstr_w(lpszSection), debugstr_w(lpszEntry),
1660 debugstr_w(lpszString), debugstr_w(lpszFilename));
1662 if(!lpszFilename || !*lpszFilename)
1664 push_error(ODBC_ERROR_INVALID_STR, odbc_error_invalid_param_string);
1665 return FALSE;
1668 if ((ret = RegCreateKeyW(HKEY_CURRENT_USER, odbcW, &hkey)) == ERROR_SUCCESS)
1670 HKEY hkeyfilename;
1672 if ((ret = RegCreateKeyW(hkey, lpszFilename, &hkeyfilename)) == ERROR_SUCCESS)
1674 HKEY hkey_section;
1676 if ((ret = RegCreateKeyW(hkeyfilename, lpszSection, &hkey_section)) == ERROR_SUCCESS)
1678 if(lpszString)
1679 ret = RegSetValueExW(hkey_section, lpszEntry, 0, REG_SZ, (BYTE*)lpszString, (lstrlenW(lpszString)+1)*sizeof(WCHAR));
1680 else
1681 ret = RegSetValueExW(hkey_section, lpszEntry, 0, REG_SZ, (BYTE*)empty, sizeof(empty));
1682 RegCloseKey(hkey_section);
1685 RegCloseKey(hkeyfilename);
1688 RegCloseKey(hkey);
1691 return ret == ERROR_SUCCESS;
1694 BOOL WINAPI SQLWritePrivateProfileString(LPCSTR lpszSection, LPCSTR lpszEntry,
1695 LPCSTR lpszString, LPCSTR lpszFilename)
1697 BOOL ret;
1698 WCHAR *sect, *entry, *string, *file;
1699 clear_errors();
1700 TRACE("%s %s %s %s\n", lpszSection, lpszEntry, lpszString, lpszFilename);
1702 sect = heap_strdupAtoW(lpszSection);
1703 entry = heap_strdupAtoW(lpszEntry);
1704 string = heap_strdupAtoW(lpszString);
1705 file = heap_strdupAtoW(lpszFilename);
1707 ret = SQLWritePrivateProfileStringW(sect, entry, string, file);
1709 heap_free(sect);
1710 heap_free(entry);
1711 heap_free(string);
1712 heap_free(file);
1714 return ret;