6a3d64b7ff3ddc65dcf2db3767493143ae61d3a9
[reactos.git] / reactos / dll / win32 / odbccp32 / odbccp32.c
1 /*
2 * Implementation of the ODBC driver installer
3 *
4 * Copyright 2005 Mike McCormack for CodeWeavers
5 * Copyright 2005 Hans Leidekker
6 * Copyright 2007 Bill Medland
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #define WIN32_NO_STATUS
24
25 #include <assert.h>
26 #include <stdarg.h>
27
28 #define COBJMACROS
29 #define NONAMELESSUNION
30
31 #include <windef.h>
32 #include <winbase.h>
33 #include <winreg.h>
34 #include <winnls.h>
35 #include <wine/debug.h>
36
37 #include <odbcinst.h>
38
39 WINE_DEFAULT_DEBUG_CHANNEL(odbc);
40
41 /* Registry key names */
42 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};
43
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.
47 */
48 static UWORD config_mode = ODBC_BOTH_DSN;
49
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.
53 */
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};
63
64 /* Push an error onto the error stack, taking care of ranges etc. */
65 static void push_error(int code, LPCWSTR msg)
66 {
67 if (num_errors < sizeof error_code/sizeof error_code[0])
68 {
69 error_code[num_errors] = code;
70 error_msg[num_errors] = msg;
71 num_errors++;
72 }
73 }
74
75 /* Clear the error stack */
76 static void clear_errors(void)
77 {
78 num_errors = 0;
79 }
80
81 static inline void * heap_alloc(size_t len)
82 {
83 return HeapAlloc(GetProcessHeap(), 0, len);
84 }
85
86 static inline BOOL heap_free(void *mem)
87 {
88 return HeapFree(GetProcessHeap(), 0, mem);
89 }
90
91 static inline WCHAR *heap_strdupAtoW(const char *str)
92 {
93 LPWSTR ret = NULL;
94
95 if(str) {
96 DWORD len;
97
98 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
99 ret = heap_alloc(len*sizeof(WCHAR));
100 if(ret)
101 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
102 }
103
104 return ret;
105 }
106
107
108 BOOL WINAPI ODBCCPlApplet( LONG i, LONG j, LONG * p1, LONG * p2)
109 {
110 clear_errors();
111 FIXME( "( %d %d %p %p) : stub!\n", i, j, p1, p2);
112 return FALSE;
113 }
114
115 static LPWSTR SQLInstall_strdup_multi(LPCSTR str)
116 {
117 LPCSTR p;
118 LPWSTR ret = NULL;
119 DWORD len;
120
121 if (!str)
122 return ret;
123
124 for (p = str; *p; p += lstrlenA(p) + 1)
125 ;
126
127 len = MultiByteToWideChar(CP_ACP, 0, str, p - str, NULL, 0 );
128 ret = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
129 MultiByteToWideChar(CP_ACP, 0, str, p - str, ret, len );
130 ret[len] = 0;
131
132 return ret;
133 }
134
135 static LPWSTR SQLInstall_strdup(LPCSTR str)
136 {
137 DWORD len;
138 LPWSTR ret = NULL;
139
140 if (!str)
141 return ret;
142
143 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0 );
144 ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
145 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len );
146
147 return ret;
148 }
149
150 /* Convert the wide string or zero-length-terminated list of wide strings to a
151 * narrow string or zero-length-terminated list of narrow strings.
152 * Do not try to emulate windows undocumented excesses (e.g. adding a third \0
153 * to a list)
154 * Arguments
155 * mode Indicates the sort of string.
156 * 1 denotes that the buffers contain strings terminated by a single nul
157 * character
158 * 2 denotes that the buffers contain zero-length-terminated lists
159 * (frequently erroneously referred to as double-null-terminated)
160 * buffer The narrow-character buffer into which to place the result. This
161 * must be a non-null pointer to the first element of a buffer whose
162 * length is passed in buffer_length.
163 * str The wide-character buffer containing the string or list of strings to
164 * be converted. str_length defines how many wide characters in the
165 * buffer are to be converted, including all desired terminating nul
166 * characters.
167 * str_length Effective length of str
168 * buffer_length Length of buffer
169 * returned_length A pointer to a variable that will receive the number of
170 * narrow characters placed into the buffer. This pointer
171 * may be NULL.
172 */
173 static BOOL SQLInstall_narrow(int mode, LPSTR buffer, LPCWSTR str, WORD str_length, WORD buffer_length, WORD *returned_length)
174 {
175 LPSTR pbuf; /* allows us to allocate a temporary buffer only if needed */
176 int len; /* Length of the converted list */
177 BOOL success = FALSE;
178 assert(mode == 1 || mode == 2);
179 assert(buffer_length);
180 len = WideCharToMultiByte(CP_ACP, 0, str, str_length, 0, 0, NULL, NULL);
181 if (len > 0)
182 {
183 if (len > buffer_length)
184 {
185 pbuf = HeapAlloc(GetProcessHeap(), 0, len);
186 }
187 else
188 {
189 pbuf = buffer;
190 }
191 len = WideCharToMultiByte(CP_ACP, 0, str, str_length, pbuf, len, NULL, NULL);
192 if (len > 0)
193 {
194 if (pbuf != buffer)
195 {
196 if (buffer_length > (mode - 1))
197 {
198 memcpy (buffer, pbuf, buffer_length-mode);
199 *(buffer+buffer_length-mode) = '\0';
200 }
201 *(buffer+buffer_length-1) = '\0';
202 }
203 if (returned_length)
204 {
205 *returned_length = pbuf == buffer ? len : buffer_length;
206 }
207 success = TRUE;
208 }
209 else
210 {
211 ERR("transferring wide to narrow\n");
212 }
213 if (pbuf != buffer)
214 {
215 HeapFree(GetProcessHeap(), 0, pbuf);
216 }
217 }
218 else
219 {
220 ERR("measuring wide to narrow\n");
221 }
222 return success;
223 }
224
225 BOOL WINAPI SQLConfigDataSourceW(HWND hwndParent, WORD fRequest,
226 LPCWSTR lpszDriver, LPCWSTR lpszAttributes)
227 {
228 LPCWSTR p;
229
230 clear_errors();
231 FIXME("%p %d %s %s\n", hwndParent, fRequest, debugstr_w(lpszDriver),
232 debugstr_w(lpszAttributes));
233
234 for (p = lpszAttributes; *p; p += lstrlenW(p) + 1)
235 FIXME("%s\n", debugstr_w(p));
236
237 return TRUE;
238 }
239
240 BOOL WINAPI SQLConfigDataSource(HWND hwndParent, WORD fRequest,
241 LPCSTR lpszDriver, LPCSTR lpszAttributes)
242 {
243 FIXME("%p %d %s %s\n", hwndParent, fRequest, debugstr_a(lpszDriver),
244 debugstr_a(lpszAttributes));
245 clear_errors();
246 return TRUE;
247 }
248
249 BOOL WINAPI SQLConfigDriverW(HWND hwndParent, WORD fRequest, LPCWSTR lpszDriver,
250 LPCWSTR lpszArgs, LPWSTR lpszMsg, WORD cbMsgMax, WORD *pcbMsgOut)
251 {
252 clear_errors();
253 FIXME("(%p %d %s %s %p %d %p)\n", hwndParent, fRequest, debugstr_w(lpszDriver),
254 debugstr_w(lpszArgs), lpszMsg, cbMsgMax, pcbMsgOut);
255 return TRUE;
256 }
257
258 BOOL WINAPI SQLConfigDriver(HWND hwndParent, WORD fRequest, LPCSTR lpszDriver,
259 LPCSTR lpszArgs, LPSTR lpszMsg, WORD cbMsgMax, WORD *pcbMsgOut)
260 {
261 clear_errors();
262 FIXME("(%p %d %s %s %p %d %p)\n", hwndParent, fRequest, debugstr_a(lpszDriver),
263 debugstr_a(lpszArgs), lpszMsg, cbMsgMax, pcbMsgOut);
264 return TRUE;
265 }
266
267 BOOL WINAPI SQLCreateDataSourceW(HWND hwnd, LPCWSTR lpszDS)
268 {
269 clear_errors();
270 FIXME("%p %s\n", hwnd, debugstr_w(lpszDS));
271 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
272 return FALSE;
273 }
274
275 BOOL WINAPI SQLCreateDataSource(HWND hwnd, LPCSTR lpszDS)
276 {
277 clear_errors();
278 FIXME("%p %s\n", hwnd, debugstr_a(lpszDS));
279 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
280 return FALSE;
281 }
282
283 BOOL WINAPI SQLGetAvailableDriversW(LPCWSTR lpszInfFile, LPWSTR lpszBuf,
284 WORD cbBufMax, WORD *pcbBufOut)
285 {
286 clear_errors();
287 FIXME("%s %p %d %p\n", debugstr_w(lpszInfFile), lpszBuf, cbBufMax, pcbBufOut);
288 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
289 return FALSE;
290 }
291
292 BOOL WINAPI SQLGetAvailableDrivers(LPCSTR lpszInfFile, LPSTR lpszBuf,
293 WORD cbBufMax, WORD *pcbBufOut)
294 {
295 clear_errors();
296 FIXME("%s %p %d %p\n", debugstr_a(lpszInfFile), lpszBuf, cbBufMax, pcbBufOut);
297 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
298 return FALSE;
299 }
300
301 BOOL WINAPI SQLGetConfigMode(UWORD *pwConfigMode)
302 {
303 clear_errors();
304 TRACE("%p\n", pwConfigMode);
305 if (pwConfigMode)
306 *pwConfigMode = config_mode;
307 return TRUE;
308 }
309
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.
313 */
314 BOOL WINAPI SQLGetInstalledDriversW(LPWSTR lpszBuf, WORD cbBufMax,
315 WORD *pcbBufOut)
316 {
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 */
320
321 clear_errors();
322
323 TRACE("%p %d %p\n", lpszBuf, cbBufMax, pcbBufOut);
324
325 if (!lpszBuf || cbBufMax == 0)
326 {
327 push_error(ODBC_ERROR_INVALID_BUFF_LEN, odbc_error_invalid_buff_len);
328 }
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)
332 {
333 DWORD index = 0;
334 cbBufMax--;
335 success = TRUE;
336 while (cbBufMax > 0)
337 {
338 DWORD size_name;
339 size_name = cbBufMax;
340 if ((reg_ret = RegEnumValueW(hDrivers, index, lpszBuf, &size_name, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS)
341 {
342 index++;
343 assert (size_name < cbBufMax && *(lpszBuf + size_name) == 0);
344 size_name++;
345 cbBufMax-= size_name;
346 lpszBuf+=size_name;
347 }
348 else
349 {
350 if (reg_ret != ERROR_NO_MORE_ITEMS)
351 {
352 success = FALSE;
353 push_error(ODBC_ERROR_GENERAL_ERR, odbc_error_general_err);
354 }
355 break;
356 }
357 }
358 *lpszBuf = 0;
359 if ((reg_ret = RegCloseKey (hDrivers)) != ERROR_SUCCESS)
360 TRACE ("Error %d closing ODBC Drivers key\n", reg_ret);
361 }
362 else
363 {
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.
367 */
368 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
369 }
370 return success;
371 }
372
373 BOOL WINAPI SQLGetInstalledDrivers(LPSTR lpszBuf, WORD cbBufMax,
374 WORD *pcbBufOut)
375 {
376 BOOL ret;
377 int size_wbuf = cbBufMax;
378 LPWSTR wbuf;
379 WORD size_used;
380
381 TRACE("%p %d %p\n", lpszBuf, cbBufMax, pcbBufOut);
382
383 wbuf = HeapAlloc(GetProcessHeap(), 0, size_wbuf*sizeof(WCHAR));
384 if (wbuf)
385 {
386 ret = SQLGetInstalledDriversW(wbuf, size_wbuf, &size_used);
387 if (ret)
388 {
389 if (!(ret = SQLInstall_narrow(2, lpszBuf, wbuf, size_used, cbBufMax, pcbBufOut)))
390 {
391 push_error(ODBC_ERROR_GENERAL_ERR, odbc_error_general_err);
392 }
393 }
394 HeapFree(GetProcessHeap(), 0, wbuf);
395 /* ignore failure; we have achieved the aim */
396 }
397 else
398 {
399 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
400 ret = FALSE;
401 }
402 return ret;
403 }
404
405 int WINAPI SQLGetPrivateProfileStringW(LPCWSTR lpszSection, LPCWSTR lpszEntry,
406 LPCWSTR lpszDefault, LPCWSTR RetBuffer, int cbRetBuffer,
407 LPCWSTR lpszFilename)
408 {
409 clear_errors();
410 FIXME("%s %s %s %p %d %s\n", debugstr_w(lpszSection), debugstr_w(lpszEntry),
411 debugstr_w(lpszDefault), RetBuffer, cbRetBuffer,
412 debugstr_w(lpszFilename));
413 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
414 return FALSE;
415 }
416
417 int WINAPI SQLGetPrivateProfileString(LPCSTR lpszSection, LPCSTR lpszEntry,
418 LPCSTR lpszDefault, LPCSTR RetBuffer, int cbRetBuffer,
419 LPCSTR lpszFilename)
420 {
421 clear_errors();
422 FIXME("%s %s %s %p %d %s\n", debugstr_a(lpszSection), debugstr_a(lpszEntry),
423 debugstr_a(lpszDefault), RetBuffer, cbRetBuffer,
424 debugstr_a(lpszFilename));
425 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
426 return FALSE;
427 }
428
429 BOOL WINAPI SQLGetTranslatorW(HWND hwndParent, LPWSTR lpszName, WORD cbNameMax,
430 WORD *pcbNameOut, LPWSTR lpszPath, WORD cbPathMax,
431 WORD *pcbPathOut, DWORD *pvOption)
432 {
433 clear_errors();
434 FIXME("%p %s %d %p %p %d %p %p\n", hwndParent, debugstr_w(lpszName), cbNameMax,
435 pcbNameOut, lpszPath, cbPathMax, pcbPathOut, pvOption);
436 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
437 return FALSE;
438 }
439
440 BOOL WINAPI SQLGetTranslator(HWND hwndParent, LPSTR lpszName, WORD cbNameMax,
441 WORD *pcbNameOut, LPSTR lpszPath, WORD cbPathMax,
442 WORD *pcbPathOut, DWORD *pvOption)
443 {
444 clear_errors();
445 FIXME("%p %s %d %p %p %d %p %p\n", hwndParent, debugstr_a(lpszName), cbNameMax,
446 pcbNameOut, lpszPath, cbPathMax, pcbPathOut, pvOption);
447 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
448 return FALSE;
449 }
450
451 BOOL WINAPI SQLInstallDriverW(LPCWSTR lpszInfFile, LPCWSTR lpszDriver,
452 LPWSTR lpszPath, WORD cbPathMax, WORD * pcbPathOut)
453 {
454 DWORD usage;
455
456 clear_errors();
457 TRACE("%s %s %p %d %p\n", debugstr_w(lpszInfFile),
458 debugstr_w(lpszDriver), lpszPath, cbPathMax, pcbPathOut);
459
460 if (lpszInfFile)
461 return FALSE;
462
463 return SQLInstallDriverExW(lpszDriver, NULL, lpszPath, cbPathMax,
464 pcbPathOut, ODBC_INSTALL_COMPLETE, &usage);
465 }
466
467 BOOL WINAPI SQLInstallDriver(LPCSTR lpszInfFile, LPCSTR lpszDriver,
468 LPSTR lpszPath, WORD cbPathMax, WORD * pcbPathOut)
469 {
470 DWORD usage;
471
472 clear_errors();
473 TRACE("%s %s %p %d %p\n", debugstr_a(lpszInfFile),
474 debugstr_a(lpszDriver), lpszPath, cbPathMax, pcbPathOut);
475
476 if (lpszInfFile)
477 return FALSE;
478
479 return SQLInstallDriverEx(lpszDriver, NULL, lpszPath, cbPathMax,
480 pcbPathOut, ODBC_INSTALL_COMPLETE, &usage);
481 }
482
483 BOOL WINAPI SQLInstallDriverExW(LPCWSTR lpszDriver, LPCWSTR lpszPathIn,
484 LPWSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
485 WORD fRequest, LPDWORD lpdwUsageCount)
486 {
487 UINT len;
488 LPCWSTR p;
489 WCHAR path[MAX_PATH];
490
491 clear_errors();
492 TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszDriver),
493 debugstr_w(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
494 fRequest, lpdwUsageCount);
495
496 for (p = lpszDriver; *p; p += lstrlenW(p) + 1)
497 TRACE("%s\n", debugstr_w(p));
498
499 len = GetSystemDirectoryW(path, MAX_PATH);
500
501 if (pcbPathOut)
502 *pcbPathOut = len;
503
504 len = GetSystemDirectoryW(path, MAX_PATH);
505
506 if (lpszPathOut && cbPathOutMax > len)
507 {
508 lstrcpyW(lpszPathOut, path);
509 return TRUE;
510 }
511 return FALSE;
512 }
513
514 BOOL WINAPI SQLInstallDriverEx(LPCSTR lpszDriver, LPCSTR lpszPathIn,
515 LPSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
516 WORD fRequest, LPDWORD lpdwUsageCount)
517 {
518 LPCSTR p;
519 LPWSTR driver, pathin;
520 WCHAR pathout[MAX_PATH];
521 BOOL ret;
522 WORD cbOut = 0;
523
524 clear_errors();
525 TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszDriver),
526 debugstr_a(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
527 fRequest, lpdwUsageCount);
528
529 for (p = lpszDriver; *p; p += lstrlenA(p) + 1)
530 TRACE("%s\n", debugstr_a(p));
531
532 driver = SQLInstall_strdup_multi(lpszDriver);
533 pathin = SQLInstall_strdup(lpszPathIn);
534
535 ret = SQLInstallDriverExW(driver, pathin, pathout, MAX_PATH, &cbOut,
536 fRequest, lpdwUsageCount);
537 if (ret)
538 {
539 int len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
540 0, NULL, NULL);
541 if (len)
542 {
543 if (pcbPathOut)
544 *pcbPathOut = len - 1;
545
546 if (!lpszPathOut || cbPathOutMax < len)
547 {
548 ret = FALSE;
549 goto out;
550 }
551 len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
552 cbPathOutMax, NULL, NULL);
553 }
554 }
555
556 out:
557 HeapFree(GetProcessHeap(), 0, driver);
558 HeapFree(GetProcessHeap(), 0, pathin);
559 return ret;
560 }
561
562 BOOL WINAPI SQLInstallDriverManagerW(LPWSTR lpszPath, WORD cbPathMax,
563 WORD *pcbPathOut)
564 {
565 UINT len;
566 WCHAR path[MAX_PATH];
567
568 TRACE("(%p %d %p)\n", lpszPath, cbPathMax, pcbPathOut);
569
570 if (cbPathMax < MAX_PATH)
571 return FALSE;
572
573 clear_errors();
574
575 len = GetSystemDirectoryW(path, MAX_PATH);
576
577 if (pcbPathOut)
578 *pcbPathOut = len;
579
580 if (lpszPath && cbPathMax > len)
581 {
582 lstrcpyW(lpszPath, path);
583 return TRUE;
584 }
585 return FALSE;
586 }
587
588 BOOL WINAPI SQLInstallDriverManager(LPSTR lpszPath, WORD cbPathMax,
589 WORD *pcbPathOut)
590 {
591 BOOL ret;
592 WORD len, cbOut = 0;
593 WCHAR path[MAX_PATH];
594
595 TRACE("(%p %d %p)\n", lpszPath, cbPathMax, pcbPathOut);
596
597 if (cbPathMax < MAX_PATH)
598 return FALSE;
599
600 clear_errors();
601
602 ret = SQLInstallDriverManagerW(path, MAX_PATH, &cbOut);
603 if (ret)
604 {
605 len = WideCharToMultiByte(CP_ACP, 0, path, -1, lpszPath, 0,
606 NULL, NULL);
607 if (len)
608 {
609 if (pcbPathOut)
610 *pcbPathOut = len - 1;
611
612 if (!lpszPath || cbPathMax < len)
613 return FALSE;
614
615 len = WideCharToMultiByte(CP_ACP, 0, path, -1, lpszPath,
616 cbPathMax, NULL, NULL);
617 }
618 }
619 return ret;
620 }
621
622 BOOL WINAPI SQLInstallODBCW(HWND hwndParent, LPCWSTR lpszInfFile,
623 LPCWSTR lpszSrcPath, LPCWSTR lpszDrivers)
624 {
625 clear_errors();
626 FIXME("%p %s %s %s\n", hwndParent, debugstr_w(lpszInfFile),
627 debugstr_w(lpszSrcPath), debugstr_w(lpszDrivers));
628 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
629 return FALSE;
630 }
631
632 BOOL WINAPI SQLInstallODBC(HWND hwndParent, LPCSTR lpszInfFile,
633 LPCSTR lpszSrcPath, LPCSTR lpszDrivers)
634 {
635 clear_errors();
636 FIXME("%p %s %s %s\n", hwndParent, debugstr_a(lpszInfFile),
637 debugstr_a(lpszSrcPath), debugstr_a(lpszDrivers));
638 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
639 return FALSE;
640 }
641
642 SQLRETURN WINAPI SQLInstallerErrorW(WORD iError, DWORD *pfErrorCode,
643 LPWSTR lpszErrorMsg, WORD cbErrorMsgMax, WORD *pcbErrorMsg)
644 {
645 TRACE("%d %p %p %d %p\n", iError, pfErrorCode, lpszErrorMsg,
646 cbErrorMsgMax, pcbErrorMsg);
647
648 if (iError == 0)
649 {
650 return SQL_ERROR;
651 }
652 else if (iError <= num_errors)
653 {
654 BOOL truncated = FALSE;
655 WORD len;
656 LPCWSTR msg;
657 iError--;
658 if (pfErrorCode)
659 *pfErrorCode = error_code[iError];
660 msg = error_msg[iError];
661 len = msg ? lstrlenW(msg) : 0;
662 if (pcbErrorMsg)
663 *pcbErrorMsg = len;
664 len++;
665 if (cbErrorMsgMax < len)
666 {
667 len = cbErrorMsgMax;
668 truncated = TRUE;
669 }
670 if (lpszErrorMsg && len)
671 {
672 if (msg)
673 {
674 memcpy (lpszErrorMsg, msg, len * sizeof(WCHAR));
675 }
676 else
677 {
678 assert(len==1);
679 *lpszErrorMsg = 0;
680 }
681 }
682 else
683 {
684 /* Yes. If you pass a null pointer and a large length it is not an error! */
685 truncated = TRUE;
686 }
687
688 return truncated ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
689 }
690
691 /* 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 */
692 if (pcbErrorMsg)
693 *pcbErrorMsg = 0;
694
695 if (lpszErrorMsg && cbErrorMsgMax > 0)
696 *lpszErrorMsg = '\0';
697
698 return SQL_NO_DATA;
699 }
700
701 SQLRETURN WINAPI SQLInstallerError(WORD iError, DWORD *pfErrorCode,
702 LPSTR lpszErrorMsg, WORD cbErrorMsgMax, WORD *pcbErrorMsg)
703 {
704 SQLRETURN ret;
705 LPWSTR wbuf;
706 WORD cbwbuf;
707 TRACE("%d %p %p %d %p\n", iError, pfErrorCode, lpszErrorMsg,
708 cbErrorMsgMax, pcbErrorMsg);
709
710 wbuf = 0;
711 if (lpszErrorMsg && cbErrorMsgMax)
712 {
713 wbuf = HeapAlloc(GetProcessHeap(), 0, cbErrorMsgMax*sizeof(WCHAR));
714 if (!wbuf)
715 return SQL_ERROR;
716 }
717 ret = SQLInstallerErrorW(iError, pfErrorCode, wbuf, cbErrorMsgMax, &cbwbuf);
718 if (wbuf)
719 {
720 WORD cbBuf = 0;
721 SQLInstall_narrow(1, lpszErrorMsg, wbuf, cbwbuf+1, cbErrorMsgMax, &cbBuf);
722 HeapFree(GetProcessHeap(), 0, wbuf);
723 if (pcbErrorMsg)
724 *pcbErrorMsg = cbBuf-1;
725 }
726 return ret;
727 }
728
729 BOOL WINAPI SQLInstallTranslatorExW(LPCWSTR lpszTranslator, LPCWSTR lpszPathIn,
730 LPWSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
731 WORD fRequest, LPDWORD lpdwUsageCount)
732 {
733 UINT len;
734 LPCWSTR p;
735 WCHAR path[MAX_PATH];
736
737 clear_errors();
738 TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszTranslator),
739 debugstr_w(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
740 fRequest, lpdwUsageCount);
741
742 for (p = lpszTranslator; *p; p += lstrlenW(p) + 1)
743 TRACE("%s\n", debugstr_w(p));
744
745 len = GetSystemDirectoryW(path, MAX_PATH);
746
747 if (pcbPathOut)
748 *pcbPathOut = len;
749
750 if (lpszPathOut && cbPathOutMax > len)
751 {
752 lstrcpyW(lpszPathOut, path);
753 return TRUE;
754 }
755 return FALSE;
756 }
757
758 BOOL WINAPI SQLInstallTranslatorEx(LPCSTR lpszTranslator, LPCSTR lpszPathIn,
759 LPSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
760 WORD fRequest, LPDWORD lpdwUsageCount)
761 {
762 LPCSTR p;
763 LPWSTR translator, pathin;
764 WCHAR pathout[MAX_PATH];
765 BOOL ret;
766 WORD cbOut = 0;
767
768 clear_errors();
769 TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszTranslator),
770 debugstr_a(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
771 fRequest, lpdwUsageCount);
772
773 for (p = lpszTranslator; *p; p += lstrlenA(p) + 1)
774 TRACE("%s\n", debugstr_a(p));
775
776 translator = SQLInstall_strdup_multi(lpszTranslator);
777 pathin = SQLInstall_strdup(lpszPathIn);
778
779 ret = SQLInstallTranslatorExW(translator, pathin, pathout, MAX_PATH,
780 &cbOut, fRequest, lpdwUsageCount);
781 if (ret)
782 {
783 int len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
784 0, NULL, NULL);
785 if (len)
786 {
787 if (pcbPathOut)
788 *pcbPathOut = len - 1;
789
790 if (!lpszPathOut || cbPathOutMax < len)
791 {
792 ret = FALSE;
793 goto out;
794 }
795 len = WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
796 cbPathOutMax, NULL, NULL);
797 }
798 }
799
800 out:
801 HeapFree(GetProcessHeap(), 0, translator);
802 HeapFree(GetProcessHeap(), 0, pathin);
803 return ret;
804 }
805
806 BOOL WINAPI SQLInstallTranslator(LPCSTR lpszInfFile, LPCSTR lpszTranslator,
807 LPCSTR lpszPathIn, LPSTR lpszPathOut, WORD cbPathOutMax,
808 WORD *pcbPathOut, WORD fRequest, LPDWORD lpdwUsageCount)
809 {
810 clear_errors();
811 TRACE("%s %s %s %p %d %p %d %p\n", debugstr_a(lpszInfFile),
812 debugstr_a(lpszTranslator), debugstr_a(lpszPathIn), lpszPathOut,
813 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
814
815 if (lpszInfFile)
816 return FALSE;
817
818 return SQLInstallTranslatorEx(lpszTranslator, lpszPathIn, lpszPathOut,
819 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
820 }
821
822 BOOL WINAPI SQLInstallTranslatorW(LPCWSTR lpszInfFile, LPCWSTR lpszTranslator,
823 LPCWSTR lpszPathIn, LPWSTR lpszPathOut, WORD cbPathOutMax,
824 WORD *pcbPathOut, WORD fRequest, LPDWORD lpdwUsageCount)
825 {
826 clear_errors();
827 TRACE("%s %s %s %p %d %p %d %p\n", debugstr_w(lpszInfFile),
828 debugstr_w(lpszTranslator), debugstr_w(lpszPathIn), lpszPathOut,
829 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
830
831 if (lpszInfFile)
832 return FALSE;
833
834 return SQLInstallTranslatorExW(lpszTranslator, lpszPathIn, lpszPathOut,
835 cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
836 }
837
838 BOOL WINAPI SQLManageDataSources(HWND hwnd)
839 {
840 clear_errors();
841 FIXME("%p\n", hwnd);
842 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
843 return FALSE;
844 }
845
846 SQLRETURN WINAPI SQLPostInstallerErrorW(DWORD fErrorCode, LPCWSTR szErrorMsg)
847 {
848 FIXME("%u %s\n", fErrorCode, debugstr_w(szErrorMsg));
849 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
850 return FALSE;
851 }
852
853 SQLRETURN WINAPI SQLPostInstallerError(DWORD fErrorCode, LPCSTR szErrorMsg)
854 {
855 FIXME("%u %s\n", fErrorCode, debugstr_a(szErrorMsg));
856 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
857 return FALSE;
858 }
859
860 BOOL WINAPI SQLReadFileDSNW(LPCWSTR lpszFileName, LPCWSTR lpszAppName,
861 LPCWSTR lpszKeyName, LPWSTR lpszString, WORD cbString,
862 WORD *pcbString)
863 {
864 clear_errors();
865 FIXME("%s %s %s %s %d %p\n", debugstr_w(lpszFileName), debugstr_w(lpszAppName),
866 debugstr_w(lpszKeyName), debugstr_w(lpszString), cbString, pcbString);
867 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
868 return FALSE;
869 }
870
871 BOOL WINAPI SQLReadFileDSN(LPCSTR lpszFileName, LPCSTR lpszAppName,
872 LPCSTR lpszKeyName, LPSTR lpszString, WORD cbString,
873 WORD *pcbString)
874 {
875 clear_errors();
876 FIXME("%s %s %s %s %d %p\n", debugstr_a(lpszFileName), debugstr_a(lpszAppName),
877 debugstr_a(lpszKeyName), debugstr_a(lpszString), cbString, pcbString);
878 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
879 return FALSE;
880 }
881
882 BOOL WINAPI SQLRemoveDefaultDataSource(void)
883 {
884 clear_errors();
885 FIXME("\n");
886 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
887 return FALSE;
888 }
889
890 BOOL WINAPI SQLRemoveDriverW(LPCWSTR lpszDriver, BOOL fRemoveDSN,
891 LPDWORD lpdwUsageCount)
892 {
893 clear_errors();
894 FIXME("%s %d %p\n", debugstr_w(lpszDriver), fRemoveDSN, lpdwUsageCount);
895 if (lpdwUsageCount) *lpdwUsageCount = 1;
896 return TRUE;
897 }
898
899 BOOL WINAPI SQLRemoveDriver(LPCSTR lpszDriver, BOOL fRemoveDSN,
900 LPDWORD lpdwUsageCount)
901 {
902 clear_errors();
903 FIXME("%s %d %p\n", debugstr_a(lpszDriver), fRemoveDSN, lpdwUsageCount);
904 if (lpdwUsageCount) *lpdwUsageCount = 1;
905 return TRUE;
906 }
907
908 BOOL WINAPI SQLRemoveDriverManager(LPDWORD pdwUsageCount)
909 {
910 clear_errors();
911 FIXME("%p\n", pdwUsageCount);
912 if (pdwUsageCount) *pdwUsageCount = 1;
913 return TRUE;
914 }
915
916 BOOL WINAPI SQLRemoveDSNFromIniW(LPCWSTR lpszDSN)
917 {
918 clear_errors();
919 FIXME("%s\n", debugstr_w(lpszDSN));
920 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
921 return FALSE;
922 }
923
924 BOOL WINAPI SQLRemoveDSNFromIni(LPCSTR lpszDSN)
925 {
926 clear_errors();
927 FIXME("%s\n", debugstr_a(lpszDSN));
928 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
929 return FALSE;
930 }
931
932 BOOL WINAPI SQLRemoveTranslatorW(LPCWSTR lpszTranslator, LPDWORD lpdwUsageCount)
933 {
934 clear_errors();
935 FIXME("%s %p\n", debugstr_w(lpszTranslator), lpdwUsageCount);
936 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
937 return FALSE;
938 }
939
940 BOOL WINAPI SQLRemoveTranslator(LPCSTR lpszTranslator, LPDWORD lpdwUsageCount)
941 {
942 clear_errors();
943 FIXME("%s %p\n", debugstr_a(lpszTranslator), lpdwUsageCount);
944 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
945 return FALSE;
946 }
947
948 BOOL WINAPI SQLSetConfigMode(UWORD wConfigMode)
949 {
950 clear_errors();
951 TRACE("%u\n", wConfigMode);
952
953 if (wConfigMode > ODBC_SYSTEM_DSN)
954 {
955 push_error(ODBC_ERROR_INVALID_PARAM_SEQUENCE, odbc_error_invalid_param_sequence);
956 return FALSE;
957 }
958 else
959 {
960 config_mode = wConfigMode;
961 return TRUE;
962 }
963 }
964
965 BOOL WINAPI SQLValidDSNW(LPCWSTR lpszDSN)
966 {
967 clear_errors();
968 FIXME("%s\n", debugstr_w(lpszDSN));
969 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
970 return FALSE;
971 }
972
973 BOOL WINAPI SQLValidDSN(LPCSTR lpszDSN)
974 {
975 clear_errors();
976 FIXME("%s\n", debugstr_a(lpszDSN));
977 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
978 return FALSE;
979 }
980
981 BOOL WINAPI SQLWriteDSNToIniW(LPCWSTR lpszDSN, LPCWSTR lpszDriver)
982 {
983 clear_errors();
984 FIXME("%s %s\n", debugstr_w(lpszDSN), debugstr_w(lpszDriver));
985 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
986 return FALSE;
987 }
988
989 BOOL WINAPI SQLWriteDSNToIni(LPCSTR lpszDSN, LPCSTR lpszDriver)
990 {
991 clear_errors();
992 FIXME("%s %s\n", debugstr_a(lpszDSN), debugstr_a(lpszDriver));
993 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
994 return FALSE;
995 }
996
997 BOOL WINAPI SQLWriteFileDSNW(LPCWSTR lpszFileName, LPCWSTR lpszAppName,
998 LPCWSTR lpszKeyName, LPCWSTR lpszString)
999 {
1000 clear_errors();
1001 FIXME("%s %s %s %s\n", debugstr_w(lpszFileName), debugstr_w(lpszAppName),
1002 debugstr_w(lpszKeyName), debugstr_w(lpszString));
1003 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1004 return FALSE;
1005 }
1006
1007 BOOL WINAPI SQLWriteFileDSN(LPCSTR lpszFileName, LPCSTR lpszAppName,
1008 LPCSTR lpszKeyName, LPCSTR lpszString)
1009 {
1010 clear_errors();
1011 FIXME("%s %s %s %s\n", debugstr_a(lpszFileName), debugstr_a(lpszAppName),
1012 debugstr_a(lpszKeyName), debugstr_a(lpszString));
1013 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1014 return FALSE;
1015 }
1016
1017 BOOL WINAPI SQLWritePrivateProfileStringW(LPCWSTR lpszSection, LPCWSTR lpszEntry,
1018 LPCWSTR lpszString, LPCWSTR lpszFilename)
1019 {
1020 LONG ret;
1021 HKEY hkey;
1022 WCHAR softwareodbc[] = {'S','o','f','t','w','a','r','e','\\','O','D','B','C',0};
1023
1024 clear_errors();
1025 TRACE("%s %s %s %s\n", debugstr_w(lpszSection), debugstr_w(lpszEntry),
1026 debugstr_w(lpszString), debugstr_w(lpszFilename));
1027
1028 if(!lpszFilename || !*lpszFilename)
1029 {
1030 push_error(ODBC_ERROR_INVALID_STR, odbc_error_invalid_param_string);
1031 return FALSE;
1032 }
1033
1034 if ((ret = RegCreateKeyW(HKEY_CURRENT_USER, softwareodbc, &hkey)) == ERROR_SUCCESS)
1035 {
1036 HKEY hkeyfilename;
1037
1038 if ((ret = RegCreateKeyW(hkey, lpszFilename, &hkeyfilename)) == ERROR_SUCCESS)
1039 {
1040 HKEY hkey_section;
1041
1042 if ((ret = RegCreateKeyW(hkeyfilename, lpszSection, &hkey_section)) == ERROR_SUCCESS)
1043 {
1044 ret = RegSetValueExW(hkey_section, lpszEntry, 0, REG_SZ, (BYTE*)lpszString, (lstrlenW(lpszString)+1)*sizeof(WCHAR));
1045 RegCloseKey(hkey_section);
1046 }
1047
1048 RegCloseKey(hkeyfilename);
1049 }
1050
1051 RegCloseKey(hkey);
1052 }
1053
1054 return ret == ERROR_SUCCESS;
1055 }
1056
1057 BOOL WINAPI SQLWritePrivateProfileString(LPCSTR lpszSection, LPCSTR lpszEntry,
1058 LPCSTR lpszString, LPCSTR lpszFilename)
1059 {
1060 BOOL ret;
1061 WCHAR *sect, *entry, *string, *file;
1062 clear_errors();
1063 TRACE("%s %s %s %s\n", lpszSection, lpszEntry, lpszString, lpszFilename);
1064
1065 sect = heap_strdupAtoW(lpszSection);
1066 entry = heap_strdupAtoW(lpszEntry);
1067 string = heap_strdupAtoW(lpszString);
1068 file = heap_strdupAtoW(lpszFilename);
1069
1070 ret = SQLWritePrivateProfileStringW(sect, entry, string, file);
1071
1072 heap_free(sect);
1073 heap_free(entry);
1074 heap_free(string);
1075 heap_free(file);
1076
1077 return ret;
1078 }