ntdll: Implement RtlValidRelativeSecurityDescriptor.
[wine.git] / dlls / odbccp32 / odbccp32.c
blobddb05983166edcc6b3181e189b8961513cd9d234
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 "wine/debug.h"
34 #include "odbcinst.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(odbc);
38 /* Registry key names */
39 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};
41 /* This config mode is known to be process-wide.
42 * MSDN documentation suggests that the value is hidden somewhere in the registry but I haven't found it yet.
43 * Although both the registry and the ODBC.ini files appear to be maintained together they are not maintained automatically through the registry's IniFileMapping.
45 static UWORD config_mode = ODBC_BOTH_DSN;
47 /* MSDN documentation suggests that the error subsystem handles errors 1 to 8
48 * only and experimentation (Windows 2000) shows that the errors are process-
49 * wide so go for the simple solution; static arrays.
51 static int num_errors;
52 static int error_code[8];
53 static const WCHAR *error_msg[8];
54 static const WCHAR odbc_error_general_err[] = {'G','e','n','e','r','a','l',' ','e','r','r','o','r',0};
55 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};
56 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};
57 static const WCHAR odbc_error_out_of_mem[] = {'O','u','t',' ','o','f',' ','m','e','m','o','r','y',0};
58 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};
59 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};
61 /* Push an error onto the error stack, taking care of ranges etc. */
62 static void push_error(int code, LPCWSTR msg)
64 if (num_errors < sizeof error_code/sizeof error_code[0])
66 error_code[num_errors] = code;
67 error_msg[num_errors] = msg;
68 num_errors++;
72 /* Clear the error stack */
73 static void clear_errors(void)
75 num_errors = 0;
78 static inline void * heap_alloc(size_t len)
80 return HeapAlloc(GetProcessHeap(), 0, len);
83 static inline BOOL heap_free(void *mem)
85 return HeapFree(GetProcessHeap(), 0, mem);
88 static inline WCHAR *heap_strdupAtoW(const char *str)
90 LPWSTR ret = NULL;
92 if(str) {
93 DWORD len;
95 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
96 ret = heap_alloc(len*sizeof(WCHAR));
97 if(ret)
98 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
101 return ret;
105 BOOL WINAPI ODBCCPlApplet( LONG i, LONG j, LONG * p1, LONG * p2)
107 clear_errors();
108 FIXME( "( %d %d %p %p) : stub!\n", i, j, p1, p2);
109 return FALSE;
112 static LPWSTR SQLInstall_strdup_multi(LPCSTR str)
114 LPCSTR p;
115 LPWSTR ret = NULL;
116 DWORD len;
118 if (!str)
119 return ret;
121 for (p = str; *p; p += lstrlenA(p) + 1)
124 len = MultiByteToWideChar(CP_ACP, 0, str, p - str, NULL, 0 );
125 ret = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
126 MultiByteToWideChar(CP_ACP, 0, str, p - str, ret, len );
127 ret[len] = 0;
129 return ret;
132 static LPWSTR SQLInstall_strdup(LPCSTR str)
134 DWORD len;
135 LPWSTR ret = NULL;
137 if (!str)
138 return ret;
140 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0 );
141 ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
142 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len );
144 return ret;
147 /* Convert the wide string or zero-length-terminated list of wide strings to a
148 * narrow string or zero-length-terminated list of narrow strings.
149 * Do not try to emulate windows undocumented excesses (e.g. adding a third \0
150 * to a list)
151 * Arguments
152 * mode Indicates the sort of string.
153 * 1 denotes that the buffers contain strings terminated by a single nul
154 * character
155 * 2 denotes that the buffers contain zero-length-terminated lists
156 * (frequently erroneously referred to as double-null-terminated)
157 * buffer The narrow-character buffer into which to place the result. This
158 * must be a non-null pointer to the first element of a buffer whose
159 * length is passed in buffer_length.
160 * str The wide-character buffer containing the string or list of strings to
161 * be converted. str_length defines how many wide characters in the
162 * buffer are to be converted, including all desired terminating nul
163 * characters.
164 * str_length Effective length of str
165 * buffer_length Length of buffer
166 * returned_length A pointer to a variable that will receive the number of
167 * narrow characters placed into the buffer. This pointer
168 * may be NULL.
170 static BOOL SQLInstall_narrow(int mode, LPSTR buffer, LPCWSTR str, WORD str_length, WORD buffer_length, WORD *returned_length)
172 LPSTR pbuf; /* allows us to allocate a temporary buffer only if needed */
173 int len; /* Length of the converted list */
174 BOOL success = FALSE;
175 assert(mode == 1 || mode == 2);
176 assert(buffer_length);
177 len = WideCharToMultiByte(CP_ACP, 0, str, str_length, 0, 0, NULL, NULL);
178 if (len > 0)
180 if (len > buffer_length)
182 pbuf = HeapAlloc(GetProcessHeap(), 0, len);
184 else
186 pbuf = buffer;
188 len = WideCharToMultiByte(CP_ACP, 0, str, str_length, pbuf, len, NULL, NULL);
189 if (len > 0)
191 if (pbuf != buffer)
193 if (buffer_length > (mode - 1))
195 memcpy (buffer, pbuf, buffer_length-mode);
196 *(buffer+buffer_length-mode) = '\0';
198 *(buffer+buffer_length-1) = '\0';
200 if (returned_length)
202 *returned_length = pbuf == buffer ? len : buffer_length;
204 success = TRUE;
206 else
208 ERR("transferring wide to narrow\n");
210 if (pbuf != buffer)
212 HeapFree(GetProcessHeap(), 0, pbuf);
215 else
217 ERR("measuring wide to narrow\n");
219 return success;
222 BOOL WINAPI SQLConfigDataSourceW(HWND hwndParent, WORD fRequest,
223 LPCWSTR lpszDriver, LPCWSTR lpszAttributes)
225 LPCWSTR p;
227 clear_errors();
228 FIXME("%p %d %s %s\n", hwndParent, fRequest, debugstr_w(lpszDriver),
229 debugstr_w(lpszAttributes));
231 for (p = lpszAttributes; *p; p += lstrlenW(p) + 1)
232 FIXME("%s\n", debugstr_w(p));
234 return TRUE;
237 BOOL WINAPI SQLConfigDataSource(HWND hwndParent, WORD fRequest,
238 LPCSTR lpszDriver, LPCSTR lpszAttributes)
240 FIXME("%p %d %s %s\n", hwndParent, fRequest, debugstr_a(lpszDriver),
241 debugstr_a(lpszAttributes));
242 clear_errors();
243 return TRUE;
246 BOOL WINAPI SQLConfigDriverW(HWND hwndParent, WORD fRequest, LPCWSTR lpszDriver,
247 LPCWSTR lpszArgs, LPWSTR lpszMsg, WORD cbMsgMax, WORD *pcbMsgOut)
249 clear_errors();
250 FIXME("(%p %d %s %s %p %d %p)\n", hwndParent, fRequest, debugstr_w(lpszDriver),
251 debugstr_w(lpszArgs), lpszMsg, cbMsgMax, pcbMsgOut);
252 return TRUE;
255 BOOL WINAPI SQLConfigDriver(HWND hwndParent, WORD fRequest, LPCSTR lpszDriver,
256 LPCSTR lpszArgs, LPSTR lpszMsg, WORD cbMsgMax, WORD *pcbMsgOut)
258 clear_errors();
259 FIXME("(%p %d %s %s %p %d %p)\n", hwndParent, fRequest, debugstr_a(lpszDriver),
260 debugstr_a(lpszArgs), lpszMsg, cbMsgMax, pcbMsgOut);
261 return TRUE;
264 BOOL WINAPI SQLCreateDataSourceW(HWND hwnd, LPCWSTR lpszDS)
266 clear_errors();
267 FIXME("%p %s\n", hwnd, debugstr_w(lpszDS));
268 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
269 return FALSE;
272 BOOL WINAPI SQLCreateDataSource(HWND hwnd, LPCSTR lpszDS)
274 clear_errors();
275 FIXME("%p %s\n", hwnd, debugstr_a(lpszDS));
276 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
277 return FALSE;
280 BOOL WINAPI SQLGetAvailableDriversW(LPCWSTR lpszInfFile, LPWSTR lpszBuf,
281 WORD cbBufMax, WORD *pcbBufOut)
283 clear_errors();
284 FIXME("%s %p %d %p\n", debugstr_w(lpszInfFile), lpszBuf, cbBufMax, pcbBufOut);
285 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
286 return FALSE;
289 BOOL WINAPI SQLGetAvailableDrivers(LPCSTR lpszInfFile, LPSTR lpszBuf,
290 WORD cbBufMax, WORD *pcbBufOut)
292 clear_errors();
293 FIXME("%s %p %d %p\n", debugstr_a(lpszInfFile), lpszBuf, cbBufMax, pcbBufOut);
294 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
295 return FALSE;
298 BOOL WINAPI SQLGetConfigMode(UWORD *pwConfigMode)
300 clear_errors();
301 TRACE("%p\n", pwConfigMode);
302 if (pwConfigMode)
303 *pwConfigMode = config_mode;
304 return TRUE;
307 /* This is implemented sensibly rather than according to exact conformance to Microsoft's buggy implementations
308 * e.g. The Microsoft one occasionally actually adds a third nul character (possibly beyond the buffer).
309 * 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.
311 BOOL WINAPI SQLGetInstalledDriversW(LPWSTR lpszBuf, WORD cbBufMax,
312 WORD *pcbBufOut)
314 HKEY hDrivers; /* Registry handle to the Drivers key */
315 LONG reg_ret; /* Return code from registry functions */
316 BOOL success = FALSE; /* The value we will return */
318 clear_errors();
320 TRACE("%p %d %p\n", lpszBuf, cbBufMax, pcbBufOut);
322 if (!lpszBuf || cbBufMax == 0)
324 push_error(ODBC_ERROR_INVALID_BUFF_LEN, odbc_error_invalid_buff_len);
326 else if ((reg_ret = RegOpenKeyExW (HKEY_LOCAL_MACHINE /* The drivers does not depend on the config mode */,
327 drivers_key, 0, KEY_READ /* Maybe overkill */,
328 &hDrivers)) == ERROR_SUCCESS)
330 DWORD index = 0;
331 cbBufMax--;
332 success = TRUE;
333 while (cbBufMax > 0)
335 DWORD size_name;
336 size_name = cbBufMax;
337 if ((reg_ret = RegEnumValueW(hDrivers, index, lpszBuf, &size_name, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS)
339 index++;
340 assert (size_name < cbBufMax && *(lpszBuf + size_name) == 0);
341 size_name++;
342 cbBufMax-= size_name;
343 lpszBuf+=size_name;
345 else
347 if (reg_ret != ERROR_NO_MORE_ITEMS)
349 success = FALSE;
350 push_error(ODBC_ERROR_GENERAL_ERR, odbc_error_general_err);
352 break;
355 *lpszBuf = 0;
356 if ((reg_ret = RegCloseKey (hDrivers)) != ERROR_SUCCESS)
357 TRACE ("Error %d closing ODBC Drivers key\n", reg_ret);
359 else
361 /* MSDN states that it returns failure with COMPONENT_NOT_FOUND in this case.
362 * Version 3.525.1117.0 (Windows 2000) does not; it actually returns success.
363 * I doubt if it will actually be an issue.
365 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
367 return success;
370 BOOL WINAPI SQLGetInstalledDrivers(LPSTR lpszBuf, WORD cbBufMax,
371 WORD *pcbBufOut)
373 BOOL ret;
374 int size_wbuf = cbBufMax;
375 LPWSTR wbuf;
376 WORD size_used;
378 TRACE("%p %d %p\n", lpszBuf, cbBufMax, pcbBufOut);
380 wbuf = HeapAlloc(GetProcessHeap(), 0, size_wbuf*sizeof(WCHAR));
381 if (wbuf)
383 ret = SQLGetInstalledDriversW(wbuf, size_wbuf, &size_used);
384 if (ret)
386 if (!(ret = SQLInstall_narrow(2, lpszBuf, wbuf, size_used, cbBufMax, pcbBufOut)))
388 push_error(ODBC_ERROR_GENERAL_ERR, odbc_error_general_err);
391 HeapFree(GetProcessHeap(), 0, wbuf);
392 /* ignore failure; we have achieved the aim */
394 else
396 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
397 ret = FALSE;
399 return ret;
402 int WINAPI SQLGetPrivateProfileStringW(LPCWSTR lpszSection, LPCWSTR lpszEntry,
403 LPCWSTR lpszDefault, LPCWSTR RetBuffer, int cbRetBuffer,
404 LPCWSTR lpszFilename)
406 clear_errors();
407 FIXME("%s %s %s %p %d %s\n", debugstr_w(lpszSection), debugstr_w(lpszEntry),
408 debugstr_w(lpszDefault), RetBuffer, cbRetBuffer,
409 debugstr_w(lpszFilename));
410 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
411 return FALSE;
414 int WINAPI SQLGetPrivateProfileString(LPCSTR lpszSection, LPCSTR lpszEntry,
415 LPCSTR lpszDefault, LPCSTR RetBuffer, int cbRetBuffer,
416 LPCSTR lpszFilename)
418 clear_errors();
419 FIXME("%s %s %s %p %d %s\n", debugstr_a(lpszSection), debugstr_a(lpszEntry),
420 debugstr_a(lpszDefault), RetBuffer, cbRetBuffer,
421 debugstr_a(lpszFilename));
422 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
423 return FALSE;
426 BOOL WINAPI SQLGetTranslatorW(HWND hwndParent, LPWSTR lpszName, WORD cbNameMax,
427 WORD *pcbNameOut, LPWSTR lpszPath, WORD cbPathMax,
428 WORD *pcbPathOut, DWORD *pvOption)
430 clear_errors();
431 FIXME("%p %s %d %p %p %d %p %p\n", hwndParent, debugstr_w(lpszName), cbNameMax,
432 pcbNameOut, lpszPath, cbPathMax, pcbPathOut, pvOption);
433 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
434 return FALSE;
437 BOOL WINAPI SQLGetTranslator(HWND hwndParent, LPSTR lpszName, WORD cbNameMax,
438 WORD *pcbNameOut, LPSTR lpszPath, WORD cbPathMax,
439 WORD *pcbPathOut, DWORD *pvOption)
441 clear_errors();
442 FIXME("%p %s %d %p %p %d %p %p\n", hwndParent, debugstr_a(lpszName), cbNameMax,
443 pcbNameOut, lpszPath, cbPathMax, pcbPathOut, pvOption);
444 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
445 return FALSE;
448 BOOL WINAPI SQLInstallDriverW(LPCWSTR lpszInfFile, LPCWSTR lpszDriver,
449 LPWSTR lpszPath, WORD cbPathMax, WORD * pcbPathOut)
451 DWORD usage;
453 clear_errors();
454 TRACE("%s %s %p %d %p\n", debugstr_w(lpszInfFile),
455 debugstr_w(lpszDriver), lpszPath, cbPathMax, pcbPathOut);
457 if (lpszInfFile)
458 return FALSE;
460 return SQLInstallDriverExW(lpszDriver, NULL, lpszPath, cbPathMax,
461 pcbPathOut, ODBC_INSTALL_COMPLETE, &usage);
464 BOOL WINAPI SQLInstallDriver(LPCSTR lpszInfFile, LPCSTR lpszDriver,
465 LPSTR lpszPath, WORD cbPathMax, WORD * pcbPathOut)
467 DWORD usage;
469 clear_errors();
470 TRACE("%s %s %p %d %p\n", debugstr_a(lpszInfFile),
471 debugstr_a(lpszDriver), lpszPath, cbPathMax, pcbPathOut);
473 if (lpszInfFile)
474 return FALSE;
476 return SQLInstallDriverEx(lpszDriver, NULL, lpszPath, cbPathMax,
477 pcbPathOut, ODBC_INSTALL_COMPLETE, &usage);
480 BOOL WINAPI SQLInstallDriverExW(LPCWSTR lpszDriver, LPCWSTR lpszPathIn,
481 LPWSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
482 WORD fRequest, LPDWORD lpdwUsageCount)
484 UINT len;
485 LPCWSTR p;
486 WCHAR path[MAX_PATH];
488 clear_errors();
489 TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszDriver),
490 debugstr_w(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
491 fRequest, lpdwUsageCount);
493 for (p = lpszDriver; *p; p += lstrlenW(p) + 1)
494 TRACE("%s\n", debugstr_w(p));
496 len = GetSystemDirectoryW(path, MAX_PATH);
498 if (pcbPathOut)
499 *pcbPathOut = len;
501 len = GetSystemDirectoryW(path, MAX_PATH);
503 if (lpszPathOut && cbPathOutMax > len)
505 lstrcpyW(lpszPathOut, path);
506 return TRUE;
508 return FALSE;
511 BOOL WINAPI SQLInstallDriverEx(LPCSTR lpszDriver, LPCSTR lpszPathIn,
512 LPSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
513 WORD fRequest, LPDWORD lpdwUsageCount)
515 LPCSTR p;
516 LPWSTR driver, pathin;
517 WCHAR pathout[MAX_PATH];
518 BOOL ret;
519 WORD cbOut = 0;
521 clear_errors();
522 TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszDriver),
523 debugstr_a(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
524 fRequest, lpdwUsageCount);
526 for (p = lpszDriver; *p; p += lstrlenA(p) + 1)
527 TRACE("%s\n", debugstr_a(p));
529 driver = SQLInstall_strdup_multi(lpszDriver);
530 pathin = SQLInstall_strdup(lpszPathIn);
532 ret = SQLInstallDriverExW(driver, pathin, pathout, MAX_PATH, &cbOut,
533 fRequest, lpdwUsageCount);
534 if (ret)
536 int len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
537 0, NULL, NULL);
538 if (len)
540 if (pcbPathOut)
541 *pcbPathOut = len - 1;
543 if (!lpszPathOut || cbPathOutMax < len)
545 ret = FALSE;
546 goto out;
548 len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
549 cbPathOutMax, NULL, NULL);
553 out:
554 HeapFree(GetProcessHeap(), 0, driver);
555 HeapFree(GetProcessHeap(), 0, pathin);
556 return ret;
559 BOOL WINAPI SQLInstallDriverManagerW(LPWSTR lpszPath, WORD cbPathMax,
560 WORD *pcbPathOut)
562 UINT len;
563 WCHAR path[MAX_PATH];
565 TRACE("(%p %d %p)\n", lpszPath, cbPathMax, pcbPathOut);
567 if (cbPathMax < MAX_PATH)
568 return FALSE;
570 clear_errors();
572 len = GetSystemDirectoryW(path, MAX_PATH);
574 if (pcbPathOut)
575 *pcbPathOut = len;
577 if (lpszPath && cbPathMax > len)
579 lstrcpyW(lpszPath, path);
580 return TRUE;
582 return FALSE;
585 BOOL WINAPI SQLInstallDriverManager(LPSTR lpszPath, WORD cbPathMax,
586 WORD *pcbPathOut)
588 BOOL ret;
589 WORD len, cbOut = 0;
590 WCHAR path[MAX_PATH];
592 TRACE("(%p %d %p)\n", lpszPath, cbPathMax, pcbPathOut);
594 if (cbPathMax < MAX_PATH)
595 return FALSE;
597 clear_errors();
599 ret = SQLInstallDriverManagerW(path, MAX_PATH, &cbOut);
600 if (ret)
602 len = WideCharToMultiByte(CP_ACP, 0, path, -1, lpszPath, 0,
603 NULL, NULL);
604 if (len)
606 if (pcbPathOut)
607 *pcbPathOut = len - 1;
609 if (!lpszPath || cbPathMax < len)
610 return FALSE;
612 len = WideCharToMultiByte(CP_ACP, 0, path, -1, lpszPath,
613 cbPathMax, NULL, NULL);
616 return ret;
619 BOOL WINAPI SQLInstallODBCW(HWND hwndParent, LPCWSTR lpszInfFile,
620 LPCWSTR lpszSrcPath, LPCWSTR lpszDrivers)
622 clear_errors();
623 FIXME("%p %s %s %s\n", hwndParent, debugstr_w(lpszInfFile),
624 debugstr_w(lpszSrcPath), debugstr_w(lpszDrivers));
625 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
626 return FALSE;
629 BOOL WINAPI SQLInstallODBC(HWND hwndParent, LPCSTR lpszInfFile,
630 LPCSTR lpszSrcPath, LPCSTR lpszDrivers)
632 clear_errors();
633 FIXME("%p %s %s %s\n", hwndParent, debugstr_a(lpszInfFile),
634 debugstr_a(lpszSrcPath), debugstr_a(lpszDrivers));
635 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
636 return FALSE;
639 SQLRETURN WINAPI SQLInstallerErrorW(WORD iError, DWORD *pfErrorCode,
640 LPWSTR lpszErrorMsg, WORD cbErrorMsgMax, WORD *pcbErrorMsg)
642 TRACE("%d %p %p %d %p\n", iError, pfErrorCode, lpszErrorMsg,
643 cbErrorMsgMax, pcbErrorMsg);
645 if (iError == 0)
647 return SQL_ERROR;
649 else if (iError <= num_errors)
651 BOOL truncated = FALSE;
652 WORD len;
653 LPCWSTR msg;
654 iError--;
655 if (pfErrorCode)
656 *pfErrorCode = error_code[iError];
657 msg = error_msg[iError];
658 len = msg ? lstrlenW(msg) : 0;
659 if (pcbErrorMsg)
660 *pcbErrorMsg = len;
661 len++;
662 if (cbErrorMsgMax < len)
664 len = cbErrorMsgMax;
665 truncated = TRUE;
667 if (lpszErrorMsg && len)
669 if (msg)
671 memcpy (lpszErrorMsg, msg, len * sizeof(WCHAR));
673 else
675 assert(len==1);
676 *lpszErrorMsg = 0;
679 else
681 /* Yes. If you pass a null pointer and a large length it is not an error! */
682 truncated = TRUE;
685 return truncated ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
688 /* 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 */
689 if (pcbErrorMsg)
690 *pcbErrorMsg = 0;
692 if (lpszErrorMsg && cbErrorMsgMax > 0)
693 *lpszErrorMsg = '\0';
695 return SQL_NO_DATA;
698 SQLRETURN WINAPI SQLInstallerError(WORD iError, DWORD *pfErrorCode,
699 LPSTR lpszErrorMsg, WORD cbErrorMsgMax, WORD *pcbErrorMsg)
701 SQLRETURN ret;
702 LPWSTR wbuf;
703 WORD cbwbuf;
704 TRACE("%d %p %p %d %p\n", iError, pfErrorCode, lpszErrorMsg,
705 cbErrorMsgMax, pcbErrorMsg);
707 wbuf = 0;
708 if (lpszErrorMsg && cbErrorMsgMax)
710 wbuf = HeapAlloc(GetProcessHeap(), 0, cbErrorMsgMax*sizeof(WCHAR));
711 if (!wbuf)
712 return SQL_ERROR;
714 ret = SQLInstallerErrorW(iError, pfErrorCode, wbuf, cbErrorMsgMax, &cbwbuf);
715 if (wbuf)
717 WORD cbBuf = 0;
718 SQLInstall_narrow(1, lpszErrorMsg, wbuf, cbwbuf+1, cbErrorMsgMax, &cbBuf);
719 HeapFree(GetProcessHeap(), 0, wbuf);
720 if (pcbErrorMsg)
721 *pcbErrorMsg = cbBuf-1;
723 return ret;
726 BOOL WINAPI SQLInstallTranslatorExW(LPCWSTR lpszTranslator, LPCWSTR lpszPathIn,
727 LPWSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
728 WORD fRequest, LPDWORD lpdwUsageCount)
730 UINT len;
731 LPCWSTR p;
732 WCHAR path[MAX_PATH];
734 clear_errors();
735 TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszTranslator),
736 debugstr_w(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
737 fRequest, lpdwUsageCount);
739 for (p = lpszTranslator; *p; p += lstrlenW(p) + 1)
740 TRACE("%s\n", debugstr_w(p));
742 len = GetSystemDirectoryW(path, MAX_PATH);
744 if (pcbPathOut)
745 *pcbPathOut = len;
747 if (lpszPathOut && cbPathOutMax > len)
749 lstrcpyW(lpszPathOut, path);
750 return TRUE;
752 return FALSE;
755 BOOL WINAPI SQLInstallTranslatorEx(LPCSTR lpszTranslator, LPCSTR lpszPathIn,
756 LPSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
757 WORD fRequest, LPDWORD lpdwUsageCount)
759 LPCSTR p;
760 LPWSTR translator, pathin;
761 WCHAR pathout[MAX_PATH];
762 BOOL ret;
763 WORD cbOut = 0;
765 clear_errors();
766 TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszTranslator),
767 debugstr_a(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
768 fRequest, lpdwUsageCount);
770 for (p = lpszTranslator; *p; p += lstrlenA(p) + 1)
771 TRACE("%s\n", debugstr_a(p));
773 translator = SQLInstall_strdup_multi(lpszTranslator);
774 pathin = SQLInstall_strdup(lpszPathIn);
776 ret = SQLInstallTranslatorExW(translator, pathin, pathout, MAX_PATH,
777 &cbOut, fRequest, lpdwUsageCount);
778 if (ret)
780 int len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
781 0, NULL, NULL);
782 if (len)
784 if (pcbPathOut)
785 *pcbPathOut = len - 1;
787 if (!lpszPathOut || cbPathOutMax < len)
789 ret = FALSE;
790 goto out;
792 len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
793 cbPathOutMax, NULL, NULL);
797 out:
798 HeapFree(GetProcessHeap(), 0, translator);
799 HeapFree(GetProcessHeap(), 0, pathin);
800 return ret;
803 BOOL WINAPI SQLInstallTranslator(LPCSTR lpszInfFile, LPCSTR lpszTranslator,
804 LPCSTR lpszPathIn, LPSTR lpszPathOut, WORD cbPathOutMax,
805 WORD *pcbPathOut, WORD fRequest, LPDWORD lpdwUsageCount)
807 clear_errors();
808 TRACE("%s %s %s %p %d %p %d %p\n", debugstr_a(lpszInfFile),
809 debugstr_a(lpszTranslator), debugstr_a(lpszPathIn), lpszPathOut,
810 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
812 if (lpszInfFile)
813 return FALSE;
815 return SQLInstallTranslatorEx(lpszTranslator, lpszPathIn, lpszPathOut,
816 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
819 BOOL WINAPI SQLInstallTranslatorW(LPCWSTR lpszInfFile, LPCWSTR lpszTranslator,
820 LPCWSTR lpszPathIn, LPWSTR lpszPathOut, WORD cbPathOutMax,
821 WORD *pcbPathOut, WORD fRequest, LPDWORD lpdwUsageCount)
823 clear_errors();
824 TRACE("%s %s %s %p %d %p %d %p\n", debugstr_w(lpszInfFile),
825 debugstr_w(lpszTranslator), debugstr_w(lpszPathIn), lpszPathOut,
826 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
828 if (lpszInfFile)
829 return FALSE;
831 return SQLInstallTranslatorExW(lpszTranslator, lpszPathIn, lpszPathOut,
832 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
835 BOOL WINAPI SQLManageDataSources(HWND hwnd)
837 clear_errors();
838 FIXME("%p\n", hwnd);
839 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
840 return FALSE;
843 SQLRETURN WINAPI SQLPostInstallerErrorW(DWORD fErrorCode, LPCWSTR szErrorMsg)
845 FIXME("%u %s\n", fErrorCode, debugstr_w(szErrorMsg));
846 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
847 return FALSE;
850 SQLRETURN WINAPI SQLPostInstallerError(DWORD fErrorCode, LPCSTR szErrorMsg)
852 FIXME("%u %s\n", fErrorCode, debugstr_a(szErrorMsg));
853 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
854 return FALSE;
857 BOOL WINAPI SQLReadFileDSNW(LPCWSTR lpszFileName, LPCWSTR lpszAppName,
858 LPCWSTR lpszKeyName, LPWSTR lpszString, WORD cbString,
859 WORD *pcbString)
861 clear_errors();
862 FIXME("%s %s %s %s %d %p\n", debugstr_w(lpszFileName), debugstr_w(lpszAppName),
863 debugstr_w(lpszKeyName), debugstr_w(lpszString), cbString, pcbString);
864 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
865 return FALSE;
868 BOOL WINAPI SQLReadFileDSN(LPCSTR lpszFileName, LPCSTR lpszAppName,
869 LPCSTR lpszKeyName, LPSTR lpszString, WORD cbString,
870 WORD *pcbString)
872 clear_errors();
873 FIXME("%s %s %s %s %d %p\n", debugstr_a(lpszFileName), debugstr_a(lpszAppName),
874 debugstr_a(lpszKeyName), debugstr_a(lpszString), cbString, pcbString);
875 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
876 return FALSE;
879 BOOL WINAPI SQLRemoveDefaultDataSource(void)
881 clear_errors();
882 FIXME("\n");
883 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
884 return FALSE;
887 BOOL WINAPI SQLRemoveDriverW(LPCWSTR lpszDriver, BOOL fRemoveDSN,
888 LPDWORD lpdwUsageCount)
890 clear_errors();
891 FIXME("%s %d %p\n", debugstr_w(lpszDriver), fRemoveDSN, lpdwUsageCount);
892 if (lpdwUsageCount) *lpdwUsageCount = 1;
893 return TRUE;
896 BOOL WINAPI SQLRemoveDriver(LPCSTR lpszDriver, BOOL fRemoveDSN,
897 LPDWORD lpdwUsageCount)
899 clear_errors();
900 FIXME("%s %d %p\n", debugstr_a(lpszDriver), fRemoveDSN, lpdwUsageCount);
901 if (lpdwUsageCount) *lpdwUsageCount = 1;
902 return TRUE;
905 BOOL WINAPI SQLRemoveDriverManager(LPDWORD pdwUsageCount)
907 clear_errors();
908 FIXME("%p\n", pdwUsageCount);
909 if (pdwUsageCount) *pdwUsageCount = 1;
910 return TRUE;
913 BOOL WINAPI SQLRemoveDSNFromIniW(LPCWSTR lpszDSN)
915 clear_errors();
916 FIXME("%s\n", debugstr_w(lpszDSN));
917 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
918 return FALSE;
921 BOOL WINAPI SQLRemoveDSNFromIni(LPCSTR lpszDSN)
923 clear_errors();
924 FIXME("%s\n", debugstr_a(lpszDSN));
925 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
926 return FALSE;
929 BOOL WINAPI SQLRemoveTranslatorW(LPCWSTR lpszTranslator, LPDWORD lpdwUsageCount)
931 clear_errors();
932 FIXME("%s %p\n", debugstr_w(lpszTranslator), lpdwUsageCount);
933 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
934 return FALSE;
937 BOOL WINAPI SQLRemoveTranslator(LPCSTR lpszTranslator, LPDWORD lpdwUsageCount)
939 clear_errors();
940 FIXME("%s %p\n", debugstr_a(lpszTranslator), lpdwUsageCount);
941 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
942 return FALSE;
945 BOOL WINAPI SQLSetConfigMode(UWORD wConfigMode)
947 clear_errors();
948 TRACE("%u\n", wConfigMode);
950 if (wConfigMode > ODBC_SYSTEM_DSN)
952 push_error(ODBC_ERROR_INVALID_PARAM_SEQUENCE, odbc_error_invalid_param_sequence);
953 return FALSE;
955 else
957 config_mode = wConfigMode;
958 return TRUE;
962 BOOL WINAPI SQLValidDSNW(LPCWSTR lpszDSN)
964 clear_errors();
965 FIXME("%s\n", debugstr_w(lpszDSN));
966 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
967 return FALSE;
970 BOOL WINAPI SQLValidDSN(LPCSTR lpszDSN)
972 clear_errors();
973 FIXME("%s\n", debugstr_a(lpszDSN));
974 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
975 return FALSE;
978 BOOL WINAPI SQLWriteDSNToIniW(LPCWSTR lpszDSN, LPCWSTR lpszDriver)
980 clear_errors();
981 FIXME("%s %s\n", debugstr_w(lpszDSN), debugstr_w(lpszDriver));
982 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
983 return FALSE;
986 BOOL WINAPI SQLWriteDSNToIni(LPCSTR lpszDSN, LPCSTR lpszDriver)
988 clear_errors();
989 FIXME("%s %s\n", debugstr_a(lpszDSN), debugstr_a(lpszDriver));
990 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
991 return FALSE;
994 BOOL WINAPI SQLWriteFileDSNW(LPCWSTR lpszFileName, LPCWSTR lpszAppName,
995 LPCWSTR lpszKeyName, LPCWSTR lpszString)
997 clear_errors();
998 FIXME("%s %s %s %s\n", debugstr_w(lpszFileName), debugstr_w(lpszAppName),
999 debugstr_w(lpszKeyName), debugstr_w(lpszString));
1000 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1001 return FALSE;
1004 BOOL WINAPI SQLWriteFileDSN(LPCSTR lpszFileName, LPCSTR lpszAppName,
1005 LPCSTR lpszKeyName, LPCSTR lpszString)
1007 clear_errors();
1008 FIXME("%s %s %s %s\n", debugstr_a(lpszFileName), debugstr_a(lpszAppName),
1009 debugstr_a(lpszKeyName), debugstr_a(lpszString));
1010 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1011 return FALSE;
1014 BOOL WINAPI SQLWritePrivateProfileStringW(LPCWSTR lpszSection, LPCWSTR lpszEntry,
1015 LPCWSTR lpszString, LPCWSTR lpszFilename)
1017 LONG ret;
1018 HKEY hkey;
1019 WCHAR softwareodbc[] = {'S','o','f','t','w','a','r','e','\\','O','D','B','C',0};
1021 clear_errors();
1022 TRACE("%s %s %s %s\n", debugstr_w(lpszSection), debugstr_w(lpszEntry),
1023 debugstr_w(lpszString), debugstr_w(lpszFilename));
1025 if(!lpszFilename || !*lpszFilename)
1027 push_error(ODBC_ERROR_INVALID_STR, odbc_error_invalid_param_string);
1028 return FALSE;
1031 if ((ret = RegCreateKeyW(HKEY_CURRENT_USER, softwareodbc, &hkey)) == ERROR_SUCCESS)
1033 HKEY hkeyfilename;
1035 if ((ret = RegCreateKeyW(hkey, lpszFilename, &hkeyfilename)) == ERROR_SUCCESS)
1037 HKEY hkey_section;
1039 if ((ret = RegCreateKeyW(hkeyfilename, lpszSection, &hkey_section)) == ERROR_SUCCESS)
1041 ret = RegSetValueExW(hkey_section, lpszEntry, 0, REG_SZ, (BYTE*)lpszString, (lstrlenW(lpszString)+1)*sizeof(WCHAR));
1042 RegCloseKey(hkey_section);
1045 RegCloseKey(hkeyfilename);
1048 RegCloseKey(hkey);
1051 return ret == ERROR_SUCCESS;
1054 BOOL WINAPI SQLWritePrivateProfileString(LPCSTR lpszSection, LPCSTR lpszEntry,
1055 LPCSTR lpszString, LPCSTR lpszFilename)
1057 BOOL ret;
1058 WCHAR *sect, *entry, *string, *file;
1059 clear_errors();
1060 TRACE("%s %s %s %s\n", lpszSection, lpszEntry, lpszString, lpszFilename);
1062 sect = heap_strdupAtoW(lpszSection);
1063 entry = heap_strdupAtoW(lpszEntry);
1064 string = heap_strdupAtoW(lpszString);
1065 file = heap_strdupAtoW(lpszFilename);
1067 ret = SQLWritePrivateProfileStringW(sect, entry, string, file);
1069 heap_free(sect);
1070 heap_free(entry);
1071 heap_free(string);
1072 heap_free(file);
1074 return ret;