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 #define WIN32_NO_STATUS
34 #include <wine/debug.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};
44 /* This config mode is known to be process-wide.
45 * MSDN documentation suggests that the value is hidden somewhere in the registry but I haven't found it yet.
46 * Although both the registry and the ODBC.ini files appear to be maintained together they are not maintained automatically through the registry's IniFileMapping.
48 static UWORD config_mode
= ODBC_BOTH_DSN
;
50 /* MSDN documentation suggests that the error subsystem handles errors 1 to 8
51 * only and experimentation (Windows 2000) shows that the errors are process-
52 * wide so go for the simple solution; static arrays.
54 static int num_errors
;
55 static int error_code
[8];
56 static const WCHAR
*error_msg
[8];
57 static const WCHAR odbc_error_general_err
[] = {'G','e','n','e','r','a','l',' ','e','r','r','o','r',0};
58 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};
59 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};
60 static const WCHAR odbc_error_out_of_mem
[] = {'O','u','t',' ','o','f',' ','m','e','m','o','r','y',0};
61 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};
62 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};
64 /* Push an error onto the error stack, taking care of ranges etc. */
65 static void push_error(int code
, LPCWSTR msg
)
67 if (num_errors
< sizeof error_code
/sizeof error_code
[0])
69 error_code
[num_errors
] = code
;
70 error_msg
[num_errors
] = msg
;
75 /* Clear the error stack */
76 static void clear_errors(void)
81 static inline void * heap_alloc(size_t len
)
83 return HeapAlloc(GetProcessHeap(), 0, len
);
86 static inline BOOL
heap_free(void *mem
)
88 return HeapFree(GetProcessHeap(), 0, mem
);
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( "( %d %d %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 BOOL WINAPI
SQLConfigDataSourceW(HWND hwndParent
, WORD fRequest
,
226 LPCWSTR lpszDriver
, LPCWSTR lpszAttributes
)
231 FIXME("%p %d %s %s\n", hwndParent
, fRequest
, debugstr_w(lpszDriver
),
232 debugstr_w(lpszAttributes
));
234 for (p
= lpszAttributes
; *p
; p
+= lstrlenW(p
) + 1)
235 FIXME("%s\n", debugstr_w(p
));
240 BOOL WINAPI
SQLConfigDataSource(HWND hwndParent
, WORD fRequest
,
241 LPCSTR lpszDriver
, LPCSTR lpszAttributes
)
243 FIXME("%p %d %s %s\n", hwndParent
, fRequest
, debugstr_a(lpszDriver
),
244 debugstr_a(lpszAttributes
));
249 BOOL WINAPI
SQLConfigDriverW(HWND hwndParent
, WORD fRequest
, LPCWSTR lpszDriver
,
250 LPCWSTR lpszArgs
, LPWSTR lpszMsg
, WORD cbMsgMax
, WORD
*pcbMsgOut
)
253 FIXME("(%p %d %s %s %p %d %p)\n", hwndParent
, fRequest
, debugstr_w(lpszDriver
),
254 debugstr_w(lpszArgs
), lpszMsg
, cbMsgMax
, pcbMsgOut
);
258 BOOL WINAPI
SQLConfigDriver(HWND hwndParent
, WORD fRequest
, LPCSTR lpszDriver
,
259 LPCSTR lpszArgs
, LPSTR lpszMsg
, WORD cbMsgMax
, WORD
*pcbMsgOut
)
262 FIXME("(%p %d %s %s %p %d %p)\n", hwndParent
, fRequest
, debugstr_a(lpszDriver
),
263 debugstr_a(lpszArgs
), lpszMsg
, cbMsgMax
, pcbMsgOut
);
267 BOOL WINAPI
SQLCreateDataSourceW(HWND hwnd
, LPCWSTR lpszDS
)
270 FIXME("%p %s\n", hwnd
, debugstr_w(lpszDS
));
271 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
275 BOOL WINAPI
SQLCreateDataSource(HWND hwnd
, LPCSTR lpszDS
)
278 FIXME("%p %s\n", hwnd
, debugstr_a(lpszDS
));
279 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
283 BOOL WINAPI
SQLGetAvailableDriversW(LPCWSTR lpszInfFile
, LPWSTR lpszBuf
,
284 WORD cbBufMax
, WORD
*pcbBufOut
)
287 FIXME("%s %p %d %p\n", debugstr_w(lpszInfFile
), lpszBuf
, cbBufMax
, pcbBufOut
);
288 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
292 BOOL WINAPI
SQLGetAvailableDrivers(LPCSTR lpszInfFile
, LPSTR lpszBuf
,
293 WORD cbBufMax
, WORD
*pcbBufOut
)
296 FIXME("%s %p %d %p\n", debugstr_a(lpszInfFile
), lpszBuf
, cbBufMax
, pcbBufOut
);
297 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
301 BOOL WINAPI
SQLGetConfigMode(UWORD
*pwConfigMode
)
304 TRACE("%p\n", pwConfigMode
);
306 *pwConfigMode
= config_mode
;
310 /* This is implemented sensibly rather than according to exact conformance to Microsoft's buggy implementations
311 * e.g. The Microsoft one occasionally actually adds a third nul character (possibly beyond the buffer).
312 * e.g. If the key has no drivers then version 3.525.1117.0 does not modify the buffer at all, not even a nul character.
314 BOOL WINAPI
SQLGetInstalledDriversW(LPWSTR lpszBuf
, WORD cbBufMax
,
317 HKEY hDrivers
; /* Registry handle to the Drivers key */
318 LONG reg_ret
; /* Return code from registry functions */
319 BOOL success
= FALSE
; /* The value we will return */
323 TRACE("%p %d %p\n", lpszBuf
, cbBufMax
, pcbBufOut
);
325 if (!lpszBuf
|| cbBufMax
== 0)
327 push_error(ODBC_ERROR_INVALID_BUFF_LEN
, odbc_error_invalid_buff_len
);
329 else if ((reg_ret
= RegOpenKeyExW (HKEY_LOCAL_MACHINE
/* The drivers does not depend on the config mode */,
330 drivers_key
, 0, KEY_READ
/* Maybe overkill */,
331 &hDrivers
)) == ERROR_SUCCESS
)
339 size_name
= cbBufMax
;
340 if ((reg_ret
= RegEnumValueW(hDrivers
, index
, lpszBuf
, &size_name
, NULL
, NULL
, NULL
, NULL
)) == ERROR_SUCCESS
)
343 assert (size_name
< cbBufMax
&& *(lpszBuf
+ size_name
) == 0);
345 cbBufMax
-= size_name
;
350 if (reg_ret
!= ERROR_NO_MORE_ITEMS
)
353 push_error(ODBC_ERROR_GENERAL_ERR
, odbc_error_general_err
);
359 if ((reg_ret
= RegCloseKey (hDrivers
)) != ERROR_SUCCESS
)
360 TRACE ("Error %d closing ODBC Drivers key\n", reg_ret
);
364 /* MSDN states that it returns failure with COMPONENT_NOT_FOUND in this case.
365 * Version 3.525.1117.0 (Windows 2000) does not; it actually returns success.
366 * I doubt if it will actually be an issue.
368 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND
, odbc_error_component_not_found
);
373 BOOL WINAPI
SQLGetInstalledDrivers(LPSTR lpszBuf
, WORD cbBufMax
,
377 int size_wbuf
= cbBufMax
;
381 TRACE("%p %d %p\n", lpszBuf
, cbBufMax
, pcbBufOut
);
383 wbuf
= HeapAlloc(GetProcessHeap(), 0, size_wbuf
*sizeof(WCHAR
));
386 ret
= SQLGetInstalledDriversW(wbuf
, size_wbuf
, &size_used
);
389 if (!(ret
= SQLInstall_narrow(2, lpszBuf
, wbuf
, size_used
, cbBufMax
, pcbBufOut
)))
391 push_error(ODBC_ERROR_GENERAL_ERR
, odbc_error_general_err
);
394 HeapFree(GetProcessHeap(), 0, wbuf
);
395 /* ignore failure; we have achieved the aim */
399 push_error(ODBC_ERROR_OUT_OF_MEM
, odbc_error_out_of_mem
);
405 static HKEY
get_privateprofile_sectionkey(LPCWSTR section
, LPCWSTR filename
)
407 HKEY hkey
, hkeyfilename
, hkeysection
;
410 if (RegOpenKeyW(HKEY_CURRENT_USER
, odbcW
, &hkey
))
413 ret
= RegOpenKeyW(hkey
, filename
, &hkeyfilename
);
418 ret
= RegOpenKeyW(hkeyfilename
, section
, &hkeysection
);
419 RegCloseKey(hkeyfilename
);
421 return ret
? NULL
: hkeysection
;
424 int WINAPI
SQLGetPrivateProfileStringW(LPCWSTR section
, LPCWSTR entry
,
425 LPCWSTR defvalue
, LPWSTR buff
, int buff_len
, LPCWSTR filename
)
427 BOOL usedefault
= TRUE
;
431 TRACE("%s %s %s %p %d %s\n", debugstr_w(section
), debugstr_w(entry
),
432 debugstr_w(defvalue
), buff
, buff_len
, debugstr_w(filename
));
436 if (buff_len
<= 0 || !section
)
442 if (!defvalue
|| !buff
)
445 sectionkey
= get_privateprofile_sectionkey(section
, filename
);
452 size
= buff_len
* sizeof(*buff
);
453 if (RegGetValueW(sectionkey
, NULL
, entry
, RRF_RT_REG_SZ
, &type
, buff
, &size
) == ERROR_SUCCESS
)
456 ret
= (size
/ sizeof(*buff
)) - 1;
461 WCHAR name
[MAX_PATH
];
467 memset(buff
, 0, buff_len
);
469 namelen
= sizeof(name
);
470 while (RegEnumValueW(sectionkey
, index
, name
, &namelen
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
472 if ((ret
+ namelen
+1) > buff_len
)
475 lstrcpyW(buff
+ret
, name
);
477 namelen
= sizeof(name
);
482 RegCloseKey(sectionkey
);
485 usedefault
= entry
!= NULL
;
489 lstrcpynW(buff
, defvalue
, buff_len
);
490 ret
= lstrlenW(buff
);
496 int WINAPI
SQLGetPrivateProfileString(LPCSTR section
, LPCSTR entry
,
497 LPCSTR defvalue
, LPSTR buff
, int buff_len
, LPCSTR filename
)
499 WCHAR
*sectionW
, *filenameW
;
500 BOOL usedefault
= TRUE
;
504 TRACE("%s %s %s %p %d %s\n", debugstr_a(section
), debugstr_a(entry
),
505 debugstr_a(defvalue
), buff
, buff_len
, debugstr_a(filename
));
515 if (!section
|| !defvalue
|| !buff
)
518 sectionW
= heap_strdupAtoW(section
);
519 filenameW
= heap_strdupAtoW(filename
);
521 sectionkey
= get_privateprofile_sectionkey(sectionW
, filenameW
);
524 heap_free(filenameW
);
532 size
= buff_len
* sizeof(*buff
);
533 if (RegGetValueA(sectionkey
, NULL
, entry
, RRF_RT_REG_SZ
, &type
, buff
, &size
) == ERROR_SUCCESS
)
536 ret
= (size
/ sizeof(*buff
)) - 1;
541 char name
[MAX_PATH
] = {0};
547 memset(buff
, 0, buff_len
);
549 namelen
= sizeof(name
);
550 while (RegEnumValueA(sectionkey
, index
, name
, &namelen
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
552 if ((ret
+ namelen
+1) > buff_len
)
555 lstrcpyA(buff
+ret
, name
);
558 namelen
= sizeof(name
);
563 RegCloseKey(sectionkey
);
566 usedefault
= entry
!= NULL
;
570 lstrcpynA(buff
, defvalue
, buff_len
);
577 BOOL WINAPI
SQLGetTranslatorW(HWND hwndParent
, LPWSTR lpszName
, WORD cbNameMax
,
578 WORD
*pcbNameOut
, LPWSTR lpszPath
, WORD cbPathMax
,
579 WORD
*pcbPathOut
, DWORD
*pvOption
)
582 FIXME("%p %s %d %p %p %d %p %p\n", hwndParent
, debugstr_w(lpszName
), cbNameMax
,
583 pcbNameOut
, lpszPath
, cbPathMax
, pcbPathOut
, pvOption
);
584 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
588 BOOL WINAPI
SQLGetTranslator(HWND hwndParent
, LPSTR lpszName
, WORD cbNameMax
,
589 WORD
*pcbNameOut
, LPSTR lpszPath
, WORD cbPathMax
,
590 WORD
*pcbPathOut
, DWORD
*pvOption
)
593 FIXME("%p %s %d %p %p %d %p %p\n", hwndParent
, debugstr_a(lpszName
), cbNameMax
,
594 pcbNameOut
, lpszPath
, cbPathMax
, pcbPathOut
, pvOption
);
595 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
599 BOOL WINAPI
SQLInstallDriverW(LPCWSTR lpszInfFile
, LPCWSTR lpszDriver
,
600 LPWSTR lpszPath
, WORD cbPathMax
, WORD
* pcbPathOut
)
605 TRACE("%s %s %p %d %p\n", debugstr_w(lpszInfFile
),
606 debugstr_w(lpszDriver
), lpszPath
, cbPathMax
, pcbPathOut
);
611 return SQLInstallDriverExW(lpszDriver
, NULL
, lpszPath
, cbPathMax
,
612 pcbPathOut
, ODBC_INSTALL_COMPLETE
, &usage
);
615 BOOL WINAPI
SQLInstallDriver(LPCSTR lpszInfFile
, LPCSTR lpszDriver
,
616 LPSTR lpszPath
, WORD cbPathMax
, WORD
* pcbPathOut
)
621 TRACE("%s %s %p %d %p\n", debugstr_a(lpszInfFile
),
622 debugstr_a(lpszDriver
), lpszPath
, cbPathMax
, pcbPathOut
);
627 return SQLInstallDriverEx(lpszDriver
, NULL
, lpszPath
, cbPathMax
,
628 pcbPathOut
, ODBC_INSTALL_COMPLETE
, &usage
);
631 BOOL WINAPI
SQLInstallDriverExW(LPCWSTR lpszDriver
, LPCWSTR lpszPathIn
,
632 LPWSTR lpszPathOut
, WORD cbPathOutMax
, WORD
*pcbPathOut
,
633 WORD fRequest
, LPDWORD lpdwUsageCount
)
637 WCHAR path
[MAX_PATH
];
640 TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszDriver
),
641 debugstr_w(lpszPathIn
), lpszPathOut
, cbPathOutMax
, pcbPathOut
,
642 fRequest
, lpdwUsageCount
);
644 for (p
= lpszDriver
; *p
; p
+= lstrlenW(p
) + 1)
645 TRACE("%s\n", debugstr_w(p
));
647 len
= GetSystemDirectoryW(path
, MAX_PATH
);
652 len
= GetSystemDirectoryW(path
, MAX_PATH
);
654 if (lpszPathOut
&& cbPathOutMax
> len
)
656 lstrcpyW(lpszPathOut
, path
);
662 BOOL WINAPI
SQLInstallDriverEx(LPCSTR lpszDriver
, LPCSTR lpszPathIn
,
663 LPSTR lpszPathOut
, WORD cbPathOutMax
, WORD
*pcbPathOut
,
664 WORD fRequest
, LPDWORD lpdwUsageCount
)
667 LPWSTR driver
, pathin
;
668 WCHAR pathout
[MAX_PATH
];
673 TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszDriver
),
674 debugstr_a(lpszPathIn
), lpszPathOut
, cbPathOutMax
, pcbPathOut
,
675 fRequest
, lpdwUsageCount
);
677 for (p
= lpszDriver
; *p
; p
+= lstrlenA(p
) + 1)
678 TRACE("%s\n", debugstr_a(p
));
680 driver
= SQLInstall_strdup_multi(lpszDriver
);
681 pathin
= SQLInstall_strdup(lpszPathIn
);
683 ret
= SQLInstallDriverExW(driver
, pathin
, pathout
, MAX_PATH
, &cbOut
,
684 fRequest
, lpdwUsageCount
);
687 int len
= WideCharToMultiByte(CP_ACP
, 0, pathout
, -1, lpszPathOut
,
692 *pcbPathOut
= len
- 1;
694 if (!lpszPathOut
|| cbPathOutMax
< len
)
699 len
= WideCharToMultiByte(CP_ACP
, 0, pathout
, -1, lpszPathOut
,
700 cbPathOutMax
, NULL
, NULL
);
705 HeapFree(GetProcessHeap(), 0, driver
);
706 HeapFree(GetProcessHeap(), 0, pathin
);
710 BOOL WINAPI
SQLInstallDriverManagerW(LPWSTR lpszPath
, WORD cbPathMax
,
714 WCHAR path
[MAX_PATH
];
716 TRACE("(%p %d %p)\n", lpszPath
, cbPathMax
, pcbPathOut
);
718 if (cbPathMax
< MAX_PATH
)
723 len
= GetSystemDirectoryW(path
, MAX_PATH
);
728 if (lpszPath
&& cbPathMax
> len
)
730 lstrcpyW(lpszPath
, path
);
736 BOOL WINAPI
SQLInstallDriverManager(LPSTR lpszPath
, WORD cbPathMax
,
741 WCHAR path
[MAX_PATH
];
743 TRACE("(%p %d %p)\n", lpszPath
, cbPathMax
, pcbPathOut
);
745 if (cbPathMax
< MAX_PATH
)
750 ret
= SQLInstallDriverManagerW(path
, MAX_PATH
, &cbOut
);
753 len
= WideCharToMultiByte(CP_ACP
, 0, path
, -1, lpszPath
, 0,
758 *pcbPathOut
= len
- 1;
760 if (!lpszPath
|| cbPathMax
< len
)
763 len
= WideCharToMultiByte(CP_ACP
, 0, path
, -1, lpszPath
,
764 cbPathMax
, NULL
, NULL
);
770 BOOL WINAPI
SQLInstallODBCW(HWND hwndParent
, LPCWSTR lpszInfFile
,
771 LPCWSTR lpszSrcPath
, LPCWSTR lpszDrivers
)
774 FIXME("%p %s %s %s\n", hwndParent
, debugstr_w(lpszInfFile
),
775 debugstr_w(lpszSrcPath
), debugstr_w(lpszDrivers
));
776 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
780 BOOL WINAPI
SQLInstallODBC(HWND hwndParent
, LPCSTR lpszInfFile
,
781 LPCSTR lpszSrcPath
, LPCSTR lpszDrivers
)
784 FIXME("%p %s %s %s\n", hwndParent
, debugstr_a(lpszInfFile
),
785 debugstr_a(lpszSrcPath
), debugstr_a(lpszDrivers
));
786 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
790 SQLRETURN WINAPI
SQLInstallerErrorW(WORD iError
, DWORD
*pfErrorCode
,
791 LPWSTR lpszErrorMsg
, WORD cbErrorMsgMax
, WORD
*pcbErrorMsg
)
793 TRACE("%d %p %p %d %p\n", iError
, pfErrorCode
, lpszErrorMsg
,
794 cbErrorMsgMax
, pcbErrorMsg
);
800 else if (iError
<= num_errors
)
802 BOOL truncated
= FALSE
;
807 *pfErrorCode
= error_code
[iError
];
808 msg
= error_msg
[iError
];
809 len
= msg
? lstrlenW(msg
) : 0;
813 if (cbErrorMsgMax
< len
)
818 if (lpszErrorMsg
&& len
)
822 memcpy (lpszErrorMsg
, msg
, len
* sizeof(WCHAR
));
832 /* Yes. If you pass a null pointer and a large length it is not an error! */
836 return truncated
? SQL_SUCCESS_WITH_INFO
: SQL_SUCCESS
;
839 /* 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 */
843 if (lpszErrorMsg
&& cbErrorMsgMax
> 0)
844 *lpszErrorMsg
= '\0';
849 SQLRETURN WINAPI
SQLInstallerError(WORD iError
, DWORD
*pfErrorCode
,
850 LPSTR lpszErrorMsg
, WORD cbErrorMsgMax
, WORD
*pcbErrorMsg
)
855 TRACE("%d %p %p %d %p\n", iError
, pfErrorCode
, lpszErrorMsg
,
856 cbErrorMsgMax
, pcbErrorMsg
);
859 if (lpszErrorMsg
&& cbErrorMsgMax
)
861 wbuf
= HeapAlloc(GetProcessHeap(), 0, cbErrorMsgMax
*sizeof(WCHAR
));
865 ret
= SQLInstallerErrorW(iError
, pfErrorCode
, wbuf
, cbErrorMsgMax
, &cbwbuf
);
869 SQLInstall_narrow(1, lpszErrorMsg
, wbuf
, cbwbuf
+1, cbErrorMsgMax
, &cbBuf
);
870 HeapFree(GetProcessHeap(), 0, wbuf
);
872 *pcbErrorMsg
= cbBuf
-1;
877 BOOL WINAPI
SQLInstallTranslatorExW(LPCWSTR lpszTranslator
, LPCWSTR lpszPathIn
,
878 LPWSTR lpszPathOut
, WORD cbPathOutMax
, WORD
*pcbPathOut
,
879 WORD fRequest
, LPDWORD lpdwUsageCount
)
883 WCHAR path
[MAX_PATH
];
886 TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszTranslator
),
887 debugstr_w(lpszPathIn
), lpszPathOut
, cbPathOutMax
, pcbPathOut
,
888 fRequest
, lpdwUsageCount
);
890 for (p
= lpszTranslator
; *p
; p
+= lstrlenW(p
) + 1)
891 TRACE("%s\n", debugstr_w(p
));
893 len
= GetSystemDirectoryW(path
, MAX_PATH
);
898 if (lpszPathOut
&& cbPathOutMax
> len
)
900 lstrcpyW(lpszPathOut
, path
);
906 BOOL WINAPI
SQLInstallTranslatorEx(LPCSTR lpszTranslator
, LPCSTR lpszPathIn
,
907 LPSTR lpszPathOut
, WORD cbPathOutMax
, WORD
*pcbPathOut
,
908 WORD fRequest
, LPDWORD lpdwUsageCount
)
911 LPWSTR translator
, pathin
;
912 WCHAR pathout
[MAX_PATH
];
917 TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszTranslator
),
918 debugstr_a(lpszPathIn
), lpszPathOut
, cbPathOutMax
, pcbPathOut
,
919 fRequest
, lpdwUsageCount
);
921 for (p
= lpszTranslator
; *p
; p
+= lstrlenA(p
) + 1)
922 TRACE("%s\n", debugstr_a(p
));
924 translator
= SQLInstall_strdup_multi(lpszTranslator
);
925 pathin
= SQLInstall_strdup(lpszPathIn
);
927 ret
= SQLInstallTranslatorExW(translator
, pathin
, pathout
, MAX_PATH
,
928 &cbOut
, fRequest
, lpdwUsageCount
);
931 int len
= WideCharToMultiByte(CP_ACP
, 0, pathout
, -1, lpszPathOut
,
936 *pcbPathOut
= len
- 1;
938 if (!lpszPathOut
|| cbPathOutMax
< len
)
943 len
= WideCharToMultiByte(CP_ACP
, 0, pathout
, -1, lpszPathOut
,
944 cbPathOutMax
, NULL
, NULL
);
949 HeapFree(GetProcessHeap(), 0, translator
);
950 HeapFree(GetProcessHeap(), 0, pathin
);
954 BOOL WINAPI
SQLInstallTranslator(LPCSTR lpszInfFile
, LPCSTR lpszTranslator
,
955 LPCSTR lpszPathIn
, LPSTR lpszPathOut
, WORD cbPathOutMax
,
956 WORD
*pcbPathOut
, WORD fRequest
, LPDWORD lpdwUsageCount
)
959 TRACE("%s %s %s %p %d %p %d %p\n", debugstr_a(lpszInfFile
),
960 debugstr_a(lpszTranslator
), debugstr_a(lpszPathIn
), lpszPathOut
,
961 cbPathOutMax
, pcbPathOut
, fRequest
, lpdwUsageCount
);
966 return SQLInstallTranslatorEx(lpszTranslator
, lpszPathIn
, lpszPathOut
,
967 cbPathOutMax
, pcbPathOut
, fRequest
, lpdwUsageCount
);
970 BOOL WINAPI
SQLInstallTranslatorW(LPCWSTR lpszInfFile
, LPCWSTR lpszTranslator
,
971 LPCWSTR lpszPathIn
, LPWSTR lpszPathOut
, WORD cbPathOutMax
,
972 WORD
*pcbPathOut
, WORD fRequest
, LPDWORD lpdwUsageCount
)
975 TRACE("%s %s %s %p %d %p %d %p\n", debugstr_w(lpszInfFile
),
976 debugstr_w(lpszTranslator
), debugstr_w(lpszPathIn
), lpszPathOut
,
977 cbPathOutMax
, pcbPathOut
, fRequest
, lpdwUsageCount
);
982 return SQLInstallTranslatorExW(lpszTranslator
, lpszPathIn
, lpszPathOut
,
983 cbPathOutMax
, pcbPathOut
, fRequest
, lpdwUsageCount
);
986 BOOL WINAPI
SQLManageDataSources(HWND hwnd
)
990 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
994 SQLRETURN WINAPI
SQLPostInstallerErrorW(DWORD fErrorCode
, LPCWSTR szErrorMsg
)
996 FIXME("%u %s\n", fErrorCode
, debugstr_w(szErrorMsg
));
997 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1001 SQLRETURN WINAPI
SQLPostInstallerError(DWORD fErrorCode
, LPCSTR szErrorMsg
)
1003 FIXME("%u %s\n", fErrorCode
, debugstr_a(szErrorMsg
));
1004 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1008 BOOL WINAPI
SQLReadFileDSNW(LPCWSTR lpszFileName
, LPCWSTR lpszAppName
,
1009 LPCWSTR lpszKeyName
, LPWSTR lpszString
, WORD cbString
,
1013 FIXME("%s %s %s %s %d %p\n", debugstr_w(lpszFileName
), debugstr_w(lpszAppName
),
1014 debugstr_w(lpszKeyName
), debugstr_w(lpszString
), cbString
, pcbString
);
1015 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1019 BOOL WINAPI
SQLReadFileDSN(LPCSTR lpszFileName
, LPCSTR lpszAppName
,
1020 LPCSTR lpszKeyName
, LPSTR lpszString
, WORD cbString
,
1024 FIXME("%s %s %s %s %d %p\n", debugstr_a(lpszFileName
), debugstr_a(lpszAppName
),
1025 debugstr_a(lpszKeyName
), debugstr_a(lpszString
), cbString
, pcbString
);
1026 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1030 BOOL WINAPI
SQLRemoveDefaultDataSource(void)
1034 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1038 BOOL WINAPI
SQLRemoveDriverW(LPCWSTR lpszDriver
, BOOL fRemoveDSN
,
1039 LPDWORD lpdwUsageCount
)
1042 FIXME("%s %d %p\n", debugstr_w(lpszDriver
), fRemoveDSN
, lpdwUsageCount
);
1043 if (lpdwUsageCount
) *lpdwUsageCount
= 1;
1047 BOOL WINAPI
SQLRemoveDriver(LPCSTR lpszDriver
, BOOL fRemoveDSN
,
1048 LPDWORD lpdwUsageCount
)
1051 FIXME("%s %d %p\n", debugstr_a(lpszDriver
), fRemoveDSN
, lpdwUsageCount
);
1052 if (lpdwUsageCount
) *lpdwUsageCount
= 1;
1056 BOOL WINAPI
SQLRemoveDriverManager(LPDWORD pdwUsageCount
)
1059 FIXME("%p\n", pdwUsageCount
);
1060 if (pdwUsageCount
) *pdwUsageCount
= 1;
1064 BOOL WINAPI
SQLRemoveDSNFromIniW(LPCWSTR lpszDSN
)
1067 FIXME("%s\n", debugstr_w(lpszDSN
));
1068 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1072 BOOL WINAPI
SQLRemoveDSNFromIni(LPCSTR lpszDSN
)
1075 FIXME("%s\n", debugstr_a(lpszDSN
));
1076 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1080 BOOL WINAPI
SQLRemoveTranslatorW(LPCWSTR lpszTranslator
, LPDWORD lpdwUsageCount
)
1083 FIXME("%s %p\n", debugstr_w(lpszTranslator
), lpdwUsageCount
);
1084 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1088 BOOL WINAPI
SQLRemoveTranslator(LPCSTR lpszTranslator
, LPDWORD lpdwUsageCount
)
1091 FIXME("%s %p\n", debugstr_a(lpszTranslator
), lpdwUsageCount
);
1092 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1096 BOOL WINAPI
SQLSetConfigMode(UWORD wConfigMode
)
1099 TRACE("%u\n", wConfigMode
);
1101 if (wConfigMode
> ODBC_SYSTEM_DSN
)
1103 push_error(ODBC_ERROR_INVALID_PARAM_SEQUENCE
, odbc_error_invalid_param_sequence
);
1108 config_mode
= wConfigMode
;
1113 BOOL WINAPI
SQLValidDSNW(LPCWSTR lpszDSN
)
1116 FIXME("%s\n", debugstr_w(lpszDSN
));
1117 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1121 BOOL WINAPI
SQLValidDSN(LPCSTR lpszDSN
)
1124 FIXME("%s\n", debugstr_a(lpszDSN
));
1125 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1129 BOOL WINAPI
SQLWriteDSNToIniW(LPCWSTR lpszDSN
, LPCWSTR lpszDriver
)
1132 FIXME("%s %s\n", debugstr_w(lpszDSN
), debugstr_w(lpszDriver
));
1133 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1137 BOOL WINAPI
SQLWriteDSNToIni(LPCSTR lpszDSN
, LPCSTR lpszDriver
)
1140 FIXME("%s %s\n", debugstr_a(lpszDSN
), debugstr_a(lpszDriver
));
1141 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1145 BOOL WINAPI
SQLWriteFileDSNW(LPCWSTR lpszFileName
, LPCWSTR lpszAppName
,
1146 LPCWSTR lpszKeyName
, LPCWSTR lpszString
)
1149 FIXME("%s %s %s %s\n", debugstr_w(lpszFileName
), debugstr_w(lpszAppName
),
1150 debugstr_w(lpszKeyName
), debugstr_w(lpszString
));
1151 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1155 BOOL WINAPI
SQLWriteFileDSN(LPCSTR lpszFileName
, LPCSTR lpszAppName
,
1156 LPCSTR lpszKeyName
, LPCSTR lpszString
)
1159 FIXME("%s %s %s %s\n", debugstr_a(lpszFileName
), debugstr_a(lpszAppName
),
1160 debugstr_a(lpszKeyName
), debugstr_a(lpszString
));
1161 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1165 BOOL WINAPI
SQLWritePrivateProfileStringW(LPCWSTR lpszSection
, LPCWSTR lpszEntry
,
1166 LPCWSTR lpszString
, LPCWSTR lpszFilename
)
1172 TRACE("%s %s %s %s\n", debugstr_w(lpszSection
), debugstr_w(lpszEntry
),
1173 debugstr_w(lpszString
), debugstr_w(lpszFilename
));
1175 if(!lpszFilename
|| !*lpszFilename
)
1177 push_error(ODBC_ERROR_INVALID_STR
, odbc_error_invalid_param_string
);
1181 if ((ret
= RegCreateKeyW(HKEY_CURRENT_USER
, odbcW
, &hkey
)) == ERROR_SUCCESS
)
1185 if ((ret
= RegCreateKeyW(hkey
, lpszFilename
, &hkeyfilename
)) == ERROR_SUCCESS
)
1189 if ((ret
= RegCreateKeyW(hkeyfilename
, lpszSection
, &hkey_section
)) == ERROR_SUCCESS
)
1191 ret
= RegSetValueExW(hkey_section
, lpszEntry
, 0, REG_SZ
, (BYTE
*)lpszString
, (lstrlenW(lpszString
)+1)*sizeof(WCHAR
));
1192 RegCloseKey(hkey_section
);
1195 RegCloseKey(hkeyfilename
);
1201 return ret
== ERROR_SUCCESS
;
1204 BOOL WINAPI
SQLWritePrivateProfileString(LPCSTR lpszSection
, LPCSTR lpszEntry
,
1205 LPCSTR lpszString
, LPCSTR lpszFilename
)
1208 WCHAR
*sect
, *entry
, *string
, *file
;
1210 TRACE("%s %s %s %s\n", lpszSection
, lpszEntry
, lpszString
, lpszFilename
);
1212 sect
= heap_strdupAtoW(lpszSection
);
1213 entry
= heap_strdupAtoW(lpszEntry
);
1214 string
= heap_strdupAtoW(lpszString
);
1215 file
= heap_strdupAtoW(lpszFilename
);
1217 ret
= SQLWritePrivateProfileStringW(sect
, entry
, string
, file
);