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
33 #include "wine/debug.h"
34 #include "wine/heap.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
;
85 /* Clear the error stack */
86 static void clear_errors(void)
91 static inline WCHAR
*heap_strdupAtoW(const char *str
)
98 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
99 ret
= heap_alloc(len
*sizeof(WCHAR
));
101 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
108 BOOL WINAPI
ODBCCPlApplet( LONG i
, LONG j
, LONG
* p1
, LONG
* p2
)
111 FIXME( "( %ld %ld %p %p) : stub!\n", i
, j
, p1
, p2
);
115 static LPWSTR
SQLInstall_strdup_multi(LPCSTR str
)
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
);
135 static LPWSTR
SQLInstall_strdup(LPCSTR str
)
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
);
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
155 * mode Indicates the sort of string.
156 * 1 denotes that the buffers contain strings terminated by a single nul
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
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
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
);
183 if (len
> buffer_length
)
185 pbuf
= HeapAlloc(GetProcessHeap(), 0, len
);
191 len
= WideCharToMultiByte(CP_ACP
, 0, str
, str_length
, pbuf
, len
, NULL
, NULL
);
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';
205 *returned_length
= pbuf
== buffer
? len
: buffer_length
;
211 ERR("transferring wide to narrow\n");
215 HeapFree(GetProcessHeap(), 0, pbuf
);
220 ERR("measuring wide to narrow\n");
225 static HMODULE
load_config_driver(const WCHAR
*driver
)
227 static WCHAR reg_driver
[] = {'d','r','i','v','e','r',0};
230 WCHAR
*filename
= NULL
;
231 DWORD size
= 0, type
;
234 if ((ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, odbcini
, &hkey
)) == ERROR_SUCCESS
)
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
);
245 push_error(ODBC_ERROR_INVALID_DSN
, odbc_error_invalid_dsn
);
250 filename
= HeapAlloc(GetProcessHeap(), 0, size
);
253 RegCloseKey(hkeydriver
);
255 push_error(ODBC_ERROR_OUT_OF_MEM
, odbc_error_out_of_mem
);
259 ret
= RegGetValueW(hkeydriver
, NULL
, reg_driver
, RRF_RT_REG_SZ
, &type
, filename
, &size
);
261 RegCloseKey(hkeydriver
);
267 if(ret
!= ERROR_SUCCESS
)
269 HeapFree(GetProcessHeap(), 0, filename
);
270 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND
, odbc_error_component_not_found
);
274 hmod
= LoadLibraryW(filename
);
275 HeapFree(GetProcessHeap(), 0, filename
);
278 push_error(ODBC_ERROR_LOAD_LIB_FAILED
, odbc_error_load_lib_failed
);
283 static BOOL
write_config_value(const WCHAR
*driver
, const WCHAR
*args
)
286 HKEY hkey
, hkeydriver
;
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
));
301 push_error(ODBC_ERROR_OUT_OF_MEM
, odbc_error_out_of_mem
);
304 lstrcpyW(name
, args
);
306 divider
= wcschr(name
,'=');
309 push_error(ODBC_ERROR_INVALID_KEYWORD_VALUE
, odbc_error_invalid_keyword
);
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");
322 RegCloseKey(hkeydriver
);
328 if(ret
!= ERROR_SUCCESS
)
329 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND
, odbc_error_component_not_found
);
331 return ret
== ERROR_SUCCESS
;
334 RegCloseKey(hkeydriver
);
341 static WORD
map_request(WORD request
)
346 case ODBC_ADD_SYS_DSN
:
349 case ODBC_CONFIG_DSN
:
350 case ODBC_CONFIG_SYS_DSN
:
351 return ODBC_CONFIG_DSN
;
353 case ODBC_REMOVE_DSN
:
354 case ODBC_REMOVE_SYS_DSN
:
355 return ODBC_REMOVE_DSN
;
358 FIXME("unhandled request %u\n", request
);
363 static UWORD
get_config_mode(WORD request
)
365 if (request
== ODBC_ADD_DSN
|| request
== ODBC_CONFIG_DSN
|| request
== ODBC_REMOVE_DSN
) return ODBC_USER_DSN
;
366 return ODBC_SYSTEM_DSN
;
369 BOOL WINAPI
SQLConfigDataSourceW(HWND hwnd
, WORD request
, LPCWSTR driver
, LPCWSTR attributes
)
373 UWORD config_mode_prev
= config_mode
;
376 TRACE("%p, %d, %s, %s\n", hwnd
, request
, debugstr_w(driver
), debugstr_w(attributes
));
380 for (p
= attributes
; *p
; p
+= lstrlenW(p
) + 1)
381 TRACE("%s\n", debugstr_w(p
));
386 mapped_request
= map_request(request
);
390 mod
= load_config_driver(driver
);
394 config_mode
= get_config_mode(request
);
396 pConfigDSNW
= (void*)GetProcAddress(mod
, "ConfigDSNW");
398 ret
= pConfigDSNW(hwnd
, mapped_request
, driver
, attributes
);
400 ERR("Failed to find ConfigDSNW\n");
402 config_mode
= config_mode_prev
;
405 push_error(ODBC_ERROR_REQUEST_FAILED
, odbc_error_request_failed
);
412 BOOL WINAPI
SQLConfigDataSource(HWND hwnd
, WORD request
, LPCSTR driver
, LPCSTR attributes
)
417 UWORD config_mode_prev
= config_mode
;
420 TRACE("%p, %d, %s, %s\n", hwnd
, request
, debugstr_a(driver
), debugstr_a(attributes
));
425 for (p
= attributes
; *p
; p
+= lstrlenA(p
) + 1)
426 TRACE("%s\n", debugstr_a(p
));
431 mapped_request
= map_request(request
);
435 driverW
= heap_strdupAtoW(driver
);
438 push_error(ODBC_ERROR_OUT_OF_MEM
, odbc_error_out_of_mem
);
442 mod
= load_config_driver(driverW
);
449 config_mode
= get_config_mode(request
);
451 pConfigDSN
= (void*)GetProcAddress(mod
, "ConfigDSN");
454 TRACE("Calling ConfigDSN\n");
455 ret
= pConfigDSN(hwnd
, mapped_request
, driver
, attributes
);
459 pConfigDSNW
= (void*)GetProcAddress(mod
, "ConfigDSNW");
463 TRACE("Calling ConfigDSNW\n");
465 attr
= SQLInstall_strdup_multi(attributes
);
467 ret
= pConfigDSNW(hwnd
, mapped_request
, driverW
, attr
);
472 config_mode
= config_mode_prev
;
475 push_error(ODBC_ERROR_REQUEST_FAILED
, odbc_error_request_failed
);
483 BOOL WINAPI
SQLConfigDriverW(HWND hwnd
, WORD request
, LPCWSTR driver
,
484 LPCWSTR args
, LPWSTR msg
, WORD msgmax
, WORD
*msgout
)
486 BOOL (WINAPI
*pConfigDriverW
)(HWND hwnd
, WORD request
, const WCHAR
*driver
, const WCHAR
*args
, const WCHAR
*msg
, WORD msgmax
, WORD
*msgout
);
488 BOOL funcret
= FALSE
;
491 TRACE("(%p %d %s %s %p %d %p)\n", hwnd
, request
, debugstr_w(driver
),
492 debugstr_w(args
), msg
, msgmax
, msgout
);
494 if(request
== ODBC_CONFIG_DRIVER
)
496 return write_config_value(driver
, args
);
499 hmod
= load_config_driver(driver
);
503 pConfigDriverW
= (void*)GetProcAddress(hmod
, "ConfigDriverW");
505 funcret
= pConfigDriverW(hwnd
, request
, driver
, args
, msg
, msgmax
, msgout
);
508 push_error(ODBC_ERROR_REQUEST_FAILED
, odbc_error_request_failed
);
515 BOOL WINAPI
SQLConfigDriver(HWND hwnd
, WORD request
, LPCSTR driver
,
516 LPCSTR args
, LPSTR msg
, WORD msgmax
, WORD
*msgout
)
518 BOOL (WINAPI
*pConfigDriverA
)(HWND hwnd
, WORD request
, const char *driver
, const char *args
, const char *msg
, WORD msgmax
, WORD
*msgout
);
521 BOOL funcret
= FALSE
;
524 TRACE("(%p %d %s %s %p %d %p)\n", hwnd
, request
, debugstr_a(driver
),
525 debugstr_a(args
), msg
, msgmax
, msgout
);
527 driverW
= heap_strdupAtoW(driver
);
530 push_error(ODBC_ERROR_OUT_OF_MEM
, odbc_error_out_of_mem
);
533 if(request
== ODBC_CONFIG_DRIVER
)
536 WCHAR
*argsW
= heap_strdupAtoW(args
);
539 ret
= write_config_value(driverW
, argsW
);
540 HeapFree(GetProcessHeap(), 0, argsW
);
544 push_error(ODBC_ERROR_OUT_OF_MEM
, odbc_error_out_of_mem
);
547 HeapFree(GetProcessHeap(), 0, driverW
);
552 hmod
= load_config_driver(driverW
);
553 HeapFree(GetProcessHeap(), 0, driverW
);
557 pConfigDriverA
= (void*)GetProcAddress(hmod
, "ConfigDriver");
559 funcret
= pConfigDriverA(hwnd
, request
, driver
, args
, msg
, msgmax
, msgout
);
562 push_error(ODBC_ERROR_REQUEST_FAILED
, odbc_error_request_failed
);
569 BOOL WINAPI
SQLCreateDataSourceW(HWND hwnd
, LPCWSTR lpszDS
)
572 FIXME("%p %s\n", hwnd
, debugstr_w(lpszDS
));
573 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
577 BOOL WINAPI
SQLCreateDataSource(HWND hwnd
, LPCSTR lpszDS
)
580 FIXME("%p %s\n", hwnd
, debugstr_a(lpszDS
));
581 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
585 BOOL WINAPI
SQLGetAvailableDriversW(LPCWSTR lpszInfFile
, LPWSTR lpszBuf
,
586 WORD cbBufMax
, WORD
*pcbBufOut
)
589 FIXME("%s %p %d %p\n", debugstr_w(lpszInfFile
), lpszBuf
, cbBufMax
, pcbBufOut
);
590 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
594 BOOL WINAPI
SQLGetAvailableDrivers(LPCSTR lpszInfFile
, LPSTR lpszBuf
,
595 WORD cbBufMax
, WORD
*pcbBufOut
)
598 FIXME("%s %p %d %p\n", debugstr_a(lpszInfFile
), lpszBuf
, cbBufMax
, pcbBufOut
);
599 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
603 BOOL WINAPI
SQLGetConfigMode(UWORD
*pwConfigMode
)
606 TRACE("%p\n", pwConfigMode
);
608 *pwConfigMode
= config_mode
;
612 BOOL WINAPI
SQLGetInstalledDriversW(WCHAR
*buf
, WORD size
, WORD
*sizeout
)
625 TRACE("%p %d %p\n", buf
, size
, sizeout
);
629 push_error(ODBC_ERROR_INVALID_BUFF_LEN
, odbc_error_invalid_buff_len
);
633 res
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, drivers_key
, 0, KEY_QUERY_VALUE
, &drivers
);
636 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND
, odbc_error_component_not_found
);
641 value
= heap_alloc(valuelen
* sizeof(WCHAR
));
648 res
= RegEnumValueW(drivers
, index
, value
, &len
, NULL
, NULL
, NULL
, NULL
);
649 while (res
== ERROR_MORE_DATA
)
651 value
= heap_realloc(value
, ++len
* sizeof(WCHAR
));
652 res
= RegEnumValueW(drivers
, index
, value
, &len
, NULL
, NULL
, NULL
, NULL
);
654 if (res
== ERROR_SUCCESS
)
656 lstrcpynW(buf
+ written
, value
, size
- written
);
657 written
+= min(len
+ 1, size
- written
);
659 else if (res
== ERROR_NO_MORE_ITEMS
)
663 push_error(ODBC_ERROR_GENERAL_ERR
, odbc_error_general_err
);
673 RegCloseKey(drivers
);
679 BOOL WINAPI
SQLGetInstalledDrivers(char *buf
, WORD size
, WORD
*sizeout
)
685 TRACE("%p %d %p\n", buf
, size
, sizeout
);
689 push_error(ODBC_ERROR_INVALID_BUFF_LEN
, odbc_error_invalid_buff_len
);
693 wbuf
= heap_alloc(size
* sizeof(WCHAR
));
696 push_error(ODBC_ERROR_OUT_OF_MEM
, odbc_error_out_of_mem
);
700 ret
= SQLGetInstalledDriversW(wbuf
, size
, &written
);
708 *sizeout
= WideCharToMultiByte(CP_ACP
, 0, wbuf
, written
, NULL
, 0, NULL
, NULL
);
709 WideCharToMultiByte(CP_ACP
, 0, wbuf
, written
, buf
, size
, NULL
, NULL
);
715 static HKEY
get_privateprofile_sectionkey(LPCWSTR section
, LPCWSTR filename
)
717 HKEY hkey
, hkeyfilename
, hkeysection
;
720 if (RegOpenKeyW(HKEY_CURRENT_USER
, odbcW
, &hkey
))
723 ret
= RegOpenKeyW(hkey
, filename
, &hkeyfilename
);
728 ret
= RegOpenKeyW(hkeyfilename
, section
, &hkeysection
);
729 RegCloseKey(hkeyfilename
);
731 return ret
? NULL
: hkeysection
;
734 int WINAPI
SQLGetPrivateProfileStringW(LPCWSTR section
, LPCWSTR entry
,
735 LPCWSTR defvalue
, LPWSTR buff
, int buff_len
, LPCWSTR filename
)
737 BOOL usedefault
= TRUE
;
741 TRACE("%s %s %s %p %d %s\n", debugstr_w(section
), debugstr_w(entry
),
742 debugstr_w(defvalue
), buff
, buff_len
, debugstr_w(filename
));
746 if (buff_len
<= 0 || !section
)
752 if (!defvalue
|| !buff
)
755 sectionkey
= get_privateprofile_sectionkey(section
, filename
);
762 size
= buff_len
* sizeof(*buff
);
763 if (RegGetValueW(sectionkey
, NULL
, entry
, RRF_RT_REG_SZ
, &type
, buff
, &size
) == ERROR_SUCCESS
)
766 ret
= (size
/ sizeof(*buff
)) - 1;
771 WCHAR name
[MAX_PATH
];
777 memset(buff
, 0, buff_len
);
779 namelen
= sizeof(name
);
780 while (RegEnumValueW(sectionkey
, index
, name
, &namelen
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
782 if ((ret
+ namelen
+1) > buff_len
)
785 lstrcpyW(buff
+ret
, name
);
787 namelen
= sizeof(name
);
792 RegCloseKey(sectionkey
);
795 usedefault
= entry
!= NULL
;
799 lstrcpynW(buff
, defvalue
, buff_len
);
800 ret
= lstrlenW(buff
);
806 int WINAPI
SQLGetPrivateProfileString(LPCSTR section
, LPCSTR entry
,
807 LPCSTR defvalue
, LPSTR buff
, int buff_len
, LPCSTR filename
)
809 WCHAR
*sectionW
, *filenameW
;
810 BOOL usedefault
= TRUE
;
814 TRACE("%s %s %s %p %d %s\n", debugstr_a(section
), debugstr_a(entry
),
815 debugstr_a(defvalue
), buff
, buff_len
, debugstr_a(filename
));
825 if (!section
|| !defvalue
|| !buff
)
828 sectionW
= heap_strdupAtoW(section
);
829 filenameW
= heap_strdupAtoW(filename
);
831 sectionkey
= get_privateprofile_sectionkey(sectionW
, filenameW
);
834 heap_free(filenameW
);
842 size
= buff_len
* sizeof(*buff
);
843 if (RegGetValueA(sectionkey
, NULL
, entry
, RRF_RT_REG_SZ
, &type
, buff
, &size
) == ERROR_SUCCESS
)
846 ret
= (size
/ sizeof(*buff
)) - 1;
851 char name
[MAX_PATH
] = {0};
857 memset(buff
, 0, buff_len
);
859 namelen
= sizeof(name
);
860 while (RegEnumValueA(sectionkey
, index
, name
, &namelen
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
862 if ((ret
+ namelen
+1) > buff_len
)
865 lstrcpyA(buff
+ret
, name
);
868 namelen
= sizeof(name
);
873 RegCloseKey(sectionkey
);
876 usedefault
= entry
!= NULL
;
880 lstrcpynA(buff
, defvalue
, buff_len
);
887 BOOL WINAPI
SQLGetTranslatorW(HWND hwndParent
, LPWSTR lpszName
, WORD cbNameMax
,
888 WORD
*pcbNameOut
, LPWSTR lpszPath
, WORD cbPathMax
,
889 WORD
*pcbPathOut
, DWORD
*pvOption
)
892 FIXME("%p %s %d %p %p %d %p %p\n", hwndParent
, debugstr_w(lpszName
), cbNameMax
,
893 pcbNameOut
, lpszPath
, cbPathMax
, pcbPathOut
, pvOption
);
894 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
898 BOOL WINAPI
SQLGetTranslator(HWND hwndParent
, LPSTR lpszName
, WORD cbNameMax
,
899 WORD
*pcbNameOut
, LPSTR lpszPath
, WORD cbPathMax
,
900 WORD
*pcbPathOut
, DWORD
*pvOption
)
903 FIXME("%p %s %d %p %p %d %p %p\n", hwndParent
, debugstr_a(lpszName
), cbNameMax
,
904 pcbNameOut
, lpszPath
, cbPathMax
, pcbPathOut
, pvOption
);
905 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
909 BOOL WINAPI
SQLInstallDriverW(LPCWSTR lpszInfFile
, LPCWSTR lpszDriver
,
910 LPWSTR lpszPath
, WORD cbPathMax
, WORD
* pcbPathOut
)
915 TRACE("%s %s %p %d %p\n", debugstr_w(lpszInfFile
),
916 debugstr_w(lpszDriver
), lpszPath
, cbPathMax
, pcbPathOut
);
921 return SQLInstallDriverExW(lpszDriver
, NULL
, lpszPath
, cbPathMax
,
922 pcbPathOut
, ODBC_INSTALL_COMPLETE
, &usage
);
925 BOOL WINAPI
SQLInstallDriver(LPCSTR lpszInfFile
, LPCSTR lpszDriver
,
926 LPSTR lpszPath
, WORD cbPathMax
, WORD
* pcbPathOut
)
931 TRACE("%s %s %p %d %p\n", debugstr_a(lpszInfFile
),
932 debugstr_a(lpszDriver
), lpszPath
, cbPathMax
, pcbPathOut
);
937 return SQLInstallDriverEx(lpszDriver
, NULL
, lpszPath
, cbPathMax
,
938 pcbPathOut
, ODBC_INSTALL_COMPLETE
, &usage
);
941 static void write_registry_values(const WCHAR
*regkey
, const WCHAR
*driver
, const WCHAR
*path_in
, WCHAR
*path
,
944 static const WCHAR installed
[] = {'I','n','s','t','a','l','l','e','d',0};
945 static const WCHAR slash
[] = {'\\', 0};
946 static const WCHAR driverW
[] = {'D','r','i','v','e','r',0};
947 static const WCHAR setupW
[] = {'S','e','t','u','p',0};
948 static const WCHAR translator
[] = {'T','r','a','n','s','l','a','t','o','r',0};
949 HKEY hkey
, hkeydriver
;
951 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, odbcini
, &hkey
) == ERROR_SUCCESS
)
953 if (RegCreateKeyW(hkey
, regkey
, &hkeydriver
) == ERROR_SUCCESS
)
955 if(RegSetValueExW(hkeydriver
, driver
, 0, REG_SZ
, (BYTE
*)installed
, sizeof(installed
)) != ERROR_SUCCESS
)
956 ERR("Failed to write registry installed key\n");
958 RegCloseKey(hkeydriver
);
961 if (RegCreateKeyW(hkey
, driver
, &hkeydriver
) == ERROR_SUCCESS
)
965 DWORD usagecount
= 0;
968 /* Skip name entry */
970 p
+= lstrlenW(p
) + 1;
973 GetSystemDirectoryW(path
, MAX_PATH
);
975 lstrcpyW(path
, path_in
);
978 size
= sizeof(usagecount
);
979 RegGetValueA(hkeydriver
, NULL
, "UsageCount", RRF_RT_DWORD
, &type
, &usagecount
, &size
);
980 TRACE("Usage count %ld\n", usagecount
);
982 for (; *p
; p
+= lstrlenW(p
) + 1)
984 WCHAR
*divider
= wcschr(p
,'=');
991 /* Write pair values to the registry. */
992 lstrcpynW(entry
, p
, divider
- p
+ 1);
995 TRACE("Writing pair %s,%s\n", debugstr_w(entry
), debugstr_w(divider
));
997 /* Driver, Setup, Translator entries use the system path unless a path is specified. */
998 if(lstrcmpiW(driverW
, entry
) == 0 || lstrcmpiW(setupW
, entry
) == 0 ||
999 lstrcmpiW(translator
, entry
) == 0)
1001 len
= lstrlenW(path
) + lstrlenW(slash
) + lstrlenW(divider
) + 1;
1002 value
= heap_alloc(len
* sizeof(WCHAR
));
1005 ERR("Out of memory\n");
1009 lstrcpyW(value
, path
);
1010 lstrcatW(value
, slash
);
1011 lstrcatW(value
, divider
);
1015 len
= lstrlenW(divider
) + 1;
1016 value
= heap_alloc(len
* sizeof(WCHAR
));
1017 lstrcpyW(value
, divider
);
1020 if (RegSetValueExW(hkeydriver
, entry
, 0, REG_SZ
, (BYTE
*)value
,
1021 (lstrlenW(value
)+1)*sizeof(WCHAR
)) != ERROR_SUCCESS
)
1022 ERR("Failed to write registry data %s %s\n", debugstr_w(entry
), debugstr_w(value
));
1027 ERR("No pair found. %s\n", debugstr_w(p
));
1032 /* Set Usage Count */
1034 if (RegSetValueExA(hkeydriver
, "UsageCount", 0, REG_DWORD
, (BYTE
*)&usagecount
, sizeof(usagecount
)) != ERROR_SUCCESS
)
1035 ERR("Failed to write registry UsageCount key\n");
1038 *usage_count
= usagecount
;
1040 RegCloseKey(hkeydriver
);
1047 BOOL WINAPI
SQLInstallDriverExW(LPCWSTR lpszDriver
, LPCWSTR lpszPathIn
,
1048 LPWSTR lpszPathOut
, WORD cbPathOutMax
, WORD
*pcbPathOut
,
1049 WORD fRequest
, LPDWORD lpdwUsageCount
)
1052 WCHAR path
[MAX_PATH
];
1055 TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszDriver
),
1056 debugstr_w(lpszPathIn
), lpszPathOut
, cbPathOutMax
, pcbPathOut
,
1057 fRequest
, lpdwUsageCount
);
1059 write_registry_values(odbcdrivers
, lpszDriver
, lpszPathIn
, path
, lpdwUsageCount
);
1061 len
= lstrlenW(path
);
1066 if (lpszPathOut
&& cbPathOutMax
> len
)
1068 lstrcpyW(lpszPathOut
, path
);
1074 BOOL WINAPI
SQLInstallDriverEx(LPCSTR lpszDriver
, LPCSTR lpszPathIn
,
1075 LPSTR lpszPathOut
, WORD cbPathOutMax
, WORD
*pcbPathOut
,
1076 WORD fRequest
, LPDWORD lpdwUsageCount
)
1078 LPWSTR driver
, pathin
;
1079 WCHAR pathout
[MAX_PATH
];
1084 TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszDriver
),
1085 debugstr_a(lpszPathIn
), lpszPathOut
, cbPathOutMax
, pcbPathOut
,
1086 fRequest
, lpdwUsageCount
);
1088 driver
= SQLInstall_strdup_multi(lpszDriver
);
1089 pathin
= SQLInstall_strdup(lpszPathIn
);
1091 ret
= SQLInstallDriverExW(driver
, pathin
, pathout
, MAX_PATH
, &cbOut
,
1092 fRequest
, lpdwUsageCount
);
1095 int len
= WideCharToMultiByte(CP_ACP
, 0, pathout
, -1, lpszPathOut
,
1100 *pcbPathOut
= len
- 1;
1102 if (!lpszPathOut
|| cbPathOutMax
< len
)
1107 len
= WideCharToMultiByte(CP_ACP
, 0, pathout
, -1, lpszPathOut
,
1108 cbPathOutMax
, NULL
, NULL
);
1113 HeapFree(GetProcessHeap(), 0, driver
);
1114 HeapFree(GetProcessHeap(), 0, pathin
);
1118 BOOL WINAPI
SQLInstallDriverManagerW(LPWSTR lpszPath
, WORD cbPathMax
,
1122 WCHAR path
[MAX_PATH
];
1124 TRACE("(%p %d %p)\n", lpszPath
, cbPathMax
, pcbPathOut
);
1126 if (cbPathMax
< MAX_PATH
)
1131 len
= GetSystemDirectoryW(path
, MAX_PATH
);
1136 if (lpszPath
&& cbPathMax
> len
)
1138 lstrcpyW(lpszPath
, path
);
1144 BOOL WINAPI
SQLInstallDriverManager(LPSTR lpszPath
, WORD cbPathMax
,
1148 WORD len
, cbOut
= 0;
1149 WCHAR path
[MAX_PATH
];
1151 TRACE("(%p %d %p)\n", lpszPath
, cbPathMax
, pcbPathOut
);
1153 if (cbPathMax
< MAX_PATH
)
1158 ret
= SQLInstallDriverManagerW(path
, MAX_PATH
, &cbOut
);
1161 len
= WideCharToMultiByte(CP_ACP
, 0, path
, -1, lpszPath
, 0,
1166 *pcbPathOut
= len
- 1;
1168 if (!lpszPath
|| cbPathMax
< len
)
1171 len
= WideCharToMultiByte(CP_ACP
, 0, path
, -1, lpszPath
,
1172 cbPathMax
, NULL
, NULL
);
1178 BOOL WINAPI
SQLInstallODBCW(HWND hwndParent
, LPCWSTR lpszInfFile
,
1179 LPCWSTR lpszSrcPath
, LPCWSTR lpszDrivers
)
1182 FIXME("%p %s %s %s\n", hwndParent
, debugstr_w(lpszInfFile
),
1183 debugstr_w(lpszSrcPath
), debugstr_w(lpszDrivers
));
1184 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1188 BOOL WINAPI
SQLInstallODBC(HWND hwndParent
, LPCSTR lpszInfFile
,
1189 LPCSTR lpszSrcPath
, LPCSTR lpszDrivers
)
1192 FIXME("%p %s %s %s\n", hwndParent
, debugstr_a(lpszInfFile
),
1193 debugstr_a(lpszSrcPath
), debugstr_a(lpszDrivers
));
1194 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1198 SQLRETURN WINAPI
SQLInstallerErrorW(WORD iError
, DWORD
*pfErrorCode
,
1199 LPWSTR lpszErrorMsg
, WORD cbErrorMsgMax
, WORD
*pcbErrorMsg
)
1201 TRACE("%d %p %p %d %p\n", iError
, pfErrorCode
, lpszErrorMsg
,
1202 cbErrorMsgMax
, pcbErrorMsg
);
1208 else if (iError
<= num_errors
)
1210 BOOL truncated
= FALSE
;
1215 *pfErrorCode
= error_code
[iError
];
1216 msg
= error_msg
[iError
];
1217 len
= msg
? lstrlenW(msg
) : 0;
1221 if (cbErrorMsgMax
< len
)
1223 len
= cbErrorMsgMax
;
1226 if (lpszErrorMsg
&& len
)
1230 memcpy (lpszErrorMsg
, msg
, len
* sizeof(WCHAR
));
1240 /* Yes. If you pass a null pointer and a large length it is not an error! */
1244 return truncated
? SQL_SUCCESS_WITH_INFO
: SQL_SUCCESS
;
1247 /* 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 */
1251 if (lpszErrorMsg
&& cbErrorMsgMax
> 0)
1252 *lpszErrorMsg
= '\0';
1257 SQLRETURN WINAPI
SQLInstallerError(WORD iError
, DWORD
*pfErrorCode
,
1258 LPSTR lpszErrorMsg
, WORD cbErrorMsgMax
, WORD
*pcbErrorMsg
)
1263 TRACE("%d %p %p %d %p\n", iError
, pfErrorCode
, lpszErrorMsg
,
1264 cbErrorMsgMax
, pcbErrorMsg
);
1267 if (lpszErrorMsg
&& cbErrorMsgMax
)
1269 wbuf
= HeapAlloc(GetProcessHeap(), 0, cbErrorMsgMax
*sizeof(WCHAR
));
1273 ret
= SQLInstallerErrorW(iError
, pfErrorCode
, wbuf
, cbErrorMsgMax
, &cbwbuf
);
1277 SQLInstall_narrow(1, lpszErrorMsg
, wbuf
, cbwbuf
+1, cbErrorMsgMax
, &cbBuf
);
1278 HeapFree(GetProcessHeap(), 0, wbuf
);
1280 *pcbErrorMsg
= cbBuf
-1;
1285 BOOL WINAPI
SQLInstallTranslatorExW(LPCWSTR lpszTranslator
, LPCWSTR lpszPathIn
,
1286 LPWSTR lpszPathOut
, WORD cbPathOutMax
, WORD
*pcbPathOut
,
1287 WORD fRequest
, LPDWORD lpdwUsageCount
)
1290 WCHAR path
[MAX_PATH
];
1293 TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszTranslator
),
1294 debugstr_w(lpszPathIn
), lpszPathOut
, cbPathOutMax
, pcbPathOut
,
1295 fRequest
, lpdwUsageCount
);
1297 write_registry_values(odbctranslators
, lpszTranslator
, lpszPathIn
, path
, lpdwUsageCount
);
1299 len
= lstrlenW(path
);
1304 if (lpszPathOut
&& cbPathOutMax
> len
)
1306 lstrcpyW(lpszPathOut
, path
);
1312 BOOL WINAPI
SQLInstallTranslatorEx(LPCSTR lpszTranslator
, LPCSTR lpszPathIn
,
1313 LPSTR lpszPathOut
, WORD cbPathOutMax
, WORD
*pcbPathOut
,
1314 WORD fRequest
, LPDWORD lpdwUsageCount
)
1317 LPWSTR translator
, pathin
;
1318 WCHAR pathout
[MAX_PATH
];
1323 TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszTranslator
),
1324 debugstr_a(lpszPathIn
), lpszPathOut
, cbPathOutMax
, pcbPathOut
,
1325 fRequest
, lpdwUsageCount
);
1327 for (p
= lpszTranslator
; *p
; p
+= lstrlenA(p
) + 1)
1328 TRACE("%s\n", debugstr_a(p
));
1330 translator
= SQLInstall_strdup_multi(lpszTranslator
);
1331 pathin
= SQLInstall_strdup(lpszPathIn
);
1333 ret
= SQLInstallTranslatorExW(translator
, pathin
, pathout
, MAX_PATH
,
1334 &cbOut
, fRequest
, lpdwUsageCount
);
1337 int len
= WideCharToMultiByte(CP_ACP
, 0, pathout
, -1, lpszPathOut
,
1342 *pcbPathOut
= len
- 1;
1344 if (!lpszPathOut
|| cbPathOutMax
< len
)
1349 len
= WideCharToMultiByte(CP_ACP
, 0, pathout
, -1, lpszPathOut
,
1350 cbPathOutMax
, NULL
, NULL
);
1355 HeapFree(GetProcessHeap(), 0, translator
);
1356 HeapFree(GetProcessHeap(), 0, pathin
);
1360 BOOL WINAPI
SQLInstallTranslator(LPCSTR lpszInfFile
, LPCSTR lpszTranslator
,
1361 LPCSTR lpszPathIn
, LPSTR lpszPathOut
, WORD cbPathOutMax
,
1362 WORD
*pcbPathOut
, WORD fRequest
, LPDWORD lpdwUsageCount
)
1365 TRACE("%s %s %s %p %d %p %d %p\n", debugstr_a(lpszInfFile
),
1366 debugstr_a(lpszTranslator
), debugstr_a(lpszPathIn
), lpszPathOut
,
1367 cbPathOutMax
, pcbPathOut
, fRequest
, lpdwUsageCount
);
1372 return SQLInstallTranslatorEx(lpszTranslator
, lpszPathIn
, lpszPathOut
,
1373 cbPathOutMax
, pcbPathOut
, fRequest
, lpdwUsageCount
);
1376 BOOL WINAPI
SQLInstallTranslatorW(LPCWSTR lpszInfFile
, LPCWSTR lpszTranslator
,
1377 LPCWSTR lpszPathIn
, LPWSTR lpszPathOut
, WORD cbPathOutMax
,
1378 WORD
*pcbPathOut
, WORD fRequest
, LPDWORD lpdwUsageCount
)
1381 TRACE("%s %s %s %p %d %p %d %p\n", debugstr_w(lpszInfFile
),
1382 debugstr_w(lpszTranslator
), debugstr_w(lpszPathIn
), lpszPathOut
,
1383 cbPathOutMax
, pcbPathOut
, fRequest
, lpdwUsageCount
);
1388 return SQLInstallTranslatorExW(lpszTranslator
, lpszPathIn
, lpszPathOut
,
1389 cbPathOutMax
, pcbPathOut
, fRequest
, lpdwUsageCount
);
1392 BOOL WINAPI
SQLManageDataSources(HWND hwnd
)
1395 FIXME("%p\n", hwnd
);
1396 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1400 SQLRETURN WINAPI
SQLPostInstallerErrorW(DWORD fErrorCode
, LPCWSTR szErrorMsg
)
1402 FIXME("%lu %s\n", fErrorCode
, debugstr_w(szErrorMsg
));
1403 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1407 SQLRETURN WINAPI
SQLPostInstallerError(DWORD fErrorCode
, LPCSTR szErrorMsg
)
1409 FIXME("%lu %s\n", fErrorCode
, debugstr_a(szErrorMsg
));
1410 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1414 BOOL WINAPI
SQLReadFileDSNW(LPCWSTR lpszFileName
, LPCWSTR lpszAppName
,
1415 LPCWSTR lpszKeyName
, LPWSTR lpszString
, WORD cbString
,
1419 FIXME("%s %s %s %s %d %p\n", debugstr_w(lpszFileName
), debugstr_w(lpszAppName
),
1420 debugstr_w(lpszKeyName
), debugstr_w(lpszString
), cbString
, pcbString
);
1421 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1425 BOOL WINAPI
SQLReadFileDSN(LPCSTR lpszFileName
, LPCSTR lpszAppName
,
1426 LPCSTR lpszKeyName
, LPSTR lpszString
, WORD cbString
,
1430 FIXME("%s %s %s %s %d %p\n", debugstr_a(lpszFileName
), debugstr_a(lpszAppName
),
1431 debugstr_a(lpszKeyName
), debugstr_a(lpszString
), cbString
, pcbString
);
1432 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1436 BOOL WINAPI
SQLRemoveDefaultDataSource(void)
1440 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1444 BOOL WINAPI
SQLRemoveDriverW(LPCWSTR drivername
, BOOL remove_dsn
, LPDWORD usage_count
)
1447 DWORD usagecount
= 1;
1450 TRACE("%s %d %p\n", debugstr_w(drivername
), remove_dsn
, usage_count
);
1452 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, odbcini
, &hkey
) == ERROR_SUCCESS
)
1456 if (RegOpenKeyW(hkey
, drivername
, &hkeydriver
) == ERROR_SUCCESS
)
1461 size
= sizeof(usagecount
);
1462 RegGetValueA(hkeydriver
, NULL
, "UsageCount", RRF_RT_DWORD
, &type
, &usagecount
, &size
);
1463 TRACE("Usage count %ld\n", usagecount
);
1464 count
= usagecount
- 1;
1467 if (RegSetValueExA(hkeydriver
, "UsageCount", 0, REG_DWORD
, (BYTE
*)&count
, sizeof(count
)) != ERROR_SUCCESS
)
1468 ERR("Failed to write registry UsageCount key\n");
1471 RegCloseKey(hkeydriver
);
1479 if (RegDeleteKeyW(hkey
, drivername
) != ERROR_SUCCESS
)
1480 ERR("Failed to delete registry key: %s\n", debugstr_w(drivername
));
1482 if (RegOpenKeyW(hkey
, odbcdrivers
, &hkeydriver
) == ERROR_SUCCESS
)
1484 if(RegDeleteValueW(hkeydriver
, drivername
) != ERROR_SUCCESS
)
1485 ERR("Failed to delete registry value: %s\n", debugstr_w(drivername
));
1486 RegCloseKey(hkeydriver
);
1494 *usage_count
= usagecount
;
1499 BOOL WINAPI
SQLRemoveDriver(LPCSTR lpszDriver
, BOOL fRemoveDSN
,
1500 LPDWORD lpdwUsageCount
)
1506 TRACE("%s %d %p\n", debugstr_a(lpszDriver
), fRemoveDSN
, lpdwUsageCount
);
1508 driver
= SQLInstall_strdup(lpszDriver
);
1510 ret
= SQLRemoveDriverW(driver
, fRemoveDSN
, lpdwUsageCount
);
1512 HeapFree(GetProcessHeap(), 0, driver
);
1516 BOOL WINAPI
SQLRemoveDriverManager(LPDWORD pdwUsageCount
)
1519 FIXME("%p\n", pdwUsageCount
);
1520 if (pdwUsageCount
) *pdwUsageCount
= 1;
1524 BOOL WINAPI
SQLRemoveDSNFromIniW(LPCWSTR lpszDSN
)
1528 TRACE("%s\n", debugstr_w(lpszDSN
));
1532 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, L
"Software\\ODBC\\ODBC.INI\\ODBC Data Sources", &hkey
) == ERROR_SUCCESS
)
1534 RegDeleteValueW(hkey
, lpszDSN
);
1538 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, L
"Software\\ODBC\\ODBC.INI", &hkey
) == ERROR_SUCCESS
)
1540 RegDeleteTreeW(hkey
, lpszDSN
);
1547 BOOL WINAPI
SQLRemoveDSNFromIni(LPCSTR lpszDSN
)
1552 TRACE("%s\n", debugstr_a(lpszDSN
));
1556 dsn
= SQLInstall_strdup(lpszDSN
);
1558 ret
= SQLRemoveDSNFromIniW(dsn
);
1560 push_error(ODBC_ERROR_OUT_OF_MEM
, odbc_error_out_of_mem
);
1567 BOOL WINAPI
SQLRemoveTranslatorW(const WCHAR
*translator
, DWORD
*usage_count
)
1570 DWORD usagecount
= 1;
1574 TRACE("%s %p\n", debugstr_w(translator
), usage_count
);
1576 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, odbcini
, &hkey
) == ERROR_SUCCESS
)
1580 if (RegOpenKeyW(hkey
, translator
, &hkeydriver
) == ERROR_SUCCESS
)
1585 size
= sizeof(usagecount
);
1586 RegGetValueA(hkeydriver
, NULL
, "UsageCount", RRF_RT_DWORD
, &type
, &usagecount
, &size
);
1587 TRACE("Usage count %ld\n", usagecount
);
1588 count
= usagecount
- 1;
1591 if (RegSetValueExA(hkeydriver
, "UsageCount", 0, REG_DWORD
, (BYTE
*)&count
, sizeof(count
)) != ERROR_SUCCESS
)
1592 ERR("Failed to write registry UsageCount key\n");
1595 RegCloseKey(hkeydriver
);
1603 if(RegDeleteKeyW(hkey
, translator
) != ERROR_SUCCESS
)
1605 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND
, odbc_error_component_not_found
);
1606 WARN("Failed to delete registry key: %s\n", debugstr_w(translator
));
1610 if (ret
&& RegOpenKeyW(hkey
, odbctranslators
, &hkeydriver
) == ERROR_SUCCESS
)
1612 if(RegDeleteValueW(hkeydriver
, translator
) != ERROR_SUCCESS
)
1614 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND
, odbc_error_component_not_found
);
1615 WARN("Failed to delete registry key: %s\n", debugstr_w(translator
));
1619 RegCloseKey(hkeydriver
);
1626 if (ret
&& usage_count
)
1627 *usage_count
= usagecount
;
1632 BOOL WINAPI
SQLRemoveTranslator(LPCSTR lpszTranslator
, LPDWORD lpdwUsageCount
)
1638 TRACE("%s %p\n", debugstr_a(lpszTranslator
), lpdwUsageCount
);
1640 translator
= SQLInstall_strdup(lpszTranslator
);
1641 ret
= SQLRemoveTranslatorW(translator
, lpdwUsageCount
);
1643 HeapFree(GetProcessHeap(), 0, translator
);
1647 BOOL WINAPI
SQLSetConfigMode(UWORD wConfigMode
)
1650 TRACE("%u\n", wConfigMode
);
1652 if (wConfigMode
> ODBC_SYSTEM_DSN
)
1654 push_error(ODBC_ERROR_INVALID_PARAM_SEQUENCE
, odbc_error_invalid_param_sequence
);
1659 config_mode
= wConfigMode
;
1664 BOOL WINAPI
SQLValidDSNW(LPCWSTR lpszDSN
)
1666 static const WCHAR invalid
[] = {'[',']','{','}','(',')',',',';','?','*','=','!','@','\\',0};
1668 TRACE("%s\n", debugstr_w(lpszDSN
));
1670 if(lstrlenW(lpszDSN
) > SQL_MAX_DSN_LENGTH
|| wcspbrk(lpszDSN
, invalid
) != NULL
)
1678 BOOL WINAPI
SQLValidDSN(LPCSTR lpszDSN
)
1680 static const char *invalid
= "[]{}(),;?*=!@\\";
1682 TRACE("%s\n", debugstr_a(lpszDSN
));
1684 if(strlen(lpszDSN
) > SQL_MAX_DSN_LENGTH
|| strpbrk(lpszDSN
, invalid
) != NULL
)
1692 BOOL WINAPI
SQLWriteDSNToIniW(LPCWSTR lpszDSN
, LPCWSTR lpszDriver
)
1695 HKEY hkey
, hkeydriver
;
1696 WCHAR filename
[MAX_PATH
];
1698 TRACE("%s %s\n", debugstr_w(lpszDSN
), debugstr_w(lpszDriver
));
1702 if (!SQLValidDSNW(lpszDSN
))
1704 push_error(ODBC_ERROR_INVALID_DSN
, odbc_error_invalid_dsn
);
1708 /* It doesn't matter if we cannot find the driver, windows just writes a blank value. */
1710 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, odbcini
, &hkey
) == ERROR_SUCCESS
)
1714 if (RegOpenKeyW(hkey
, lpszDriver
, &hkeydriver
) == ERROR_SUCCESS
)
1716 DWORD size
= MAX_PATH
* sizeof(WCHAR
);
1717 RegGetValueW(hkeydriver
, NULL
, L
"driver", RRF_RT_REG_SZ
, NULL
, filename
, &size
);
1718 RegCloseKey(hkeydriver
);
1723 if ((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, L
"SOFTWARE\\ODBC\\ODBC.INI", &hkey
)) == ERROR_SUCCESS
)
1727 if ((ret
= RegCreateKeyW(hkey
, L
"ODBC Data Sources", &sources
)) == ERROR_SUCCESS
)
1729 RegSetValueExW(sources
, lpszDSN
, 0, REG_SZ
, (BYTE
*)lpszDriver
, (lstrlenW(lpszDriver
)+1)*sizeof(WCHAR
));
1730 RegCloseKey(sources
);
1732 RegDeleteTreeW(hkey
, lpszDSN
);
1733 if ((ret
= RegCreateKeyW(hkey
, lpszDSN
, &hkeydriver
)) == ERROR_SUCCESS
)
1735 RegSetValueExW(sources
, L
"driver", 0, REG_SZ
, (BYTE
*)filename
, (lstrlenW(filename
)+1)*sizeof(WCHAR
));
1736 RegCloseKey(hkeydriver
);
1742 if (ret
!= ERROR_SUCCESS
)
1743 push_error(ODBC_ERROR_REQUEST_FAILED
, odbc_error_request_failed
);
1745 return ret
== ERROR_SUCCESS
;
1748 BOOL WINAPI
SQLWriteDSNToIni(LPCSTR lpszDSN
, LPCSTR lpszDriver
)
1751 WCHAR
*dsn
, *driver
;
1753 TRACE("%s %s\n", debugstr_a(lpszDSN
), debugstr_a(lpszDriver
));
1755 dsn
= SQLInstall_strdup(lpszDSN
);
1756 driver
= SQLInstall_strdup(lpszDriver
);
1758 ret
= SQLWriteDSNToIniW(dsn
, driver
);
1760 push_error(ODBC_ERROR_OUT_OF_MEM
, odbc_error_out_of_mem
);
1768 BOOL WINAPI
SQLWriteFileDSNW(LPCWSTR lpszFileName
, LPCWSTR lpszAppName
,
1769 LPCWSTR lpszKeyName
, LPCWSTR lpszString
)
1772 FIXME("%s %s %s %s\n", debugstr_w(lpszFileName
), debugstr_w(lpszAppName
),
1773 debugstr_w(lpszKeyName
), debugstr_w(lpszString
));
1774 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1778 BOOL WINAPI
SQLWriteFileDSN(LPCSTR lpszFileName
, LPCSTR lpszAppName
,
1779 LPCSTR lpszKeyName
, LPCSTR lpszString
)
1782 FIXME("%s %s %s %s\n", debugstr_a(lpszFileName
), debugstr_a(lpszAppName
),
1783 debugstr_a(lpszKeyName
), debugstr_a(lpszString
));
1784 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1788 BOOL WINAPI
SQLWritePrivateProfileStringW(LPCWSTR lpszSection
, LPCWSTR lpszEntry
,
1789 LPCWSTR lpszString
, LPCWSTR lpszFilename
)
1791 static const WCHAR empty
[] = {0};
1796 TRACE("%s %s %s %s\n", debugstr_w(lpszSection
), debugstr_w(lpszEntry
),
1797 debugstr_w(lpszString
), debugstr_w(lpszFilename
));
1799 if(!lpszFilename
|| !*lpszFilename
)
1801 push_error(ODBC_ERROR_INVALID_STR
, odbc_error_invalid_param_string
);
1805 if ((ret
= RegCreateKeyW(HKEY_CURRENT_USER
, odbcW
, &hkey
)) == ERROR_SUCCESS
)
1809 if ((ret
= RegCreateKeyW(hkey
, lpszFilename
, &hkeyfilename
)) == ERROR_SUCCESS
)
1813 if ((ret
= RegCreateKeyW(hkeyfilename
, lpszSection
, &hkey_section
)) == ERROR_SUCCESS
)
1816 ret
= RegSetValueExW(hkey_section
, lpszEntry
, 0, REG_SZ
, (BYTE
*)lpszString
, (lstrlenW(lpszString
)+1)*sizeof(WCHAR
));
1818 ret
= RegSetValueExW(hkey_section
, lpszEntry
, 0, REG_SZ
, (BYTE
*)empty
, sizeof(empty
));
1819 RegCloseKey(hkey_section
);
1822 RegCloseKey(hkeyfilename
);
1828 return ret
== ERROR_SUCCESS
;
1831 BOOL WINAPI
SQLWritePrivateProfileString(LPCSTR lpszSection
, LPCSTR lpszEntry
,
1832 LPCSTR lpszString
, LPCSTR lpszFilename
)
1835 WCHAR
*sect
, *entry
, *string
, *file
;
1837 TRACE("%s %s %s %s\n", lpszSection
, lpszEntry
, lpszString
, lpszFilename
);
1839 sect
= heap_strdupAtoW(lpszSection
);
1840 entry
= heap_strdupAtoW(lpszEntry
);
1841 string
= heap_strdupAtoW(lpszString
);
1842 file
= heap_strdupAtoW(lpszFilename
);
1844 ret
= SQLWritePrivateProfileStringW(sect
, entry
, string
, file
);