xref: /reactos/dll/win32/odbccp32/odbccp32.c (revision 64106410)
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 #include <assert.h>
24 #include <stdarg.h>
25 
26 #define COBJMACROS
27 
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "winnls.h"
32 #include "sqlext.h"
33 #ifdef __REACTOS__
34 #undef TRACE_ON
35 #endif
36 #include "wine/debug.h"
37 #include "wine/heap.h"
38 
39 #include "odbcinst.h"
40 
41 WINE_DEFAULT_DEBUG_CHANNEL(odbc);
42 
43 /* Registry key names */
44 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};
45 static const WCHAR odbcW[] = {'S','o','f','t','w','a','r','e','\\','O','D','B','C',0};
46 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};
47 static const WCHAR odbcdrivers[] = {'O','D','B','C',' ','D','r','i','v','e','r','s',0};
48 static const WCHAR odbctranslators[] = {'O','D','B','C',' ','T','r','a','n','s','l','a','t','o','r','s',0};
49 
50 /* This config mode is known to be process-wide.
51  * MSDN documentation suggests that the value is hidden somewhere in the registry but I haven't found it yet.
52  * Although both the registry and the ODBC.ini files appear to be maintained together they are not maintained automatically through the registry's IniFileMapping.
53  */
54 static UWORD config_mode = ODBC_BOTH_DSN;
55 
56 /* MSDN documentation suggests that the error subsystem handles errors 1 to 8
57  * only and experimentation (Windows 2000) shows that the errors are process-
58  * wide so go for the simple solution; static arrays.
59  */
60 static int num_errors;
61 static int error_code[8];
62 static const WCHAR *error_msg[8];
63 static const WCHAR odbc_error_general_err[] = {'G','e','n','e','r','a','l',' ','e','r','r','o','r',0};
64 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};
65 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};
66 static const WCHAR odbc_error_out_of_mem[] = {'O','u','t',' ','o','f',' ','m','e','m','o','r','y',0};
67 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};
68 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};
69 static const WCHAR odbc_error_invalid_dsn[] = {'I','n','v','a','l','i','d',' ','D','S','N',0};
70 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};
71 static const WCHAR odbc_error_request_failed[] = {'R','e','q','u','e','s','t',' ','F','a','i','l','e','d',0};
72 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};
73 
74 /* Push an error onto the error stack, taking care of ranges etc. */
push_error(int code,LPCWSTR msg)75 static void push_error(int code, LPCWSTR msg)
76 {
77     if (num_errors < ARRAY_SIZE(error_code))
78     {
79         error_code[num_errors] = code;
80         error_msg[num_errors] = msg;
81         num_errors++;
82     }
83 }
84 
85 /* Clear the error stack */
clear_errors(void)86 static void clear_errors(void)
87 {
88     num_errors = 0;
89 }
90 
heap_strdupAtoW(const char * str)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 
ODBCCPlApplet(LONG i,LONG j,LONG * p1,LONG * p2)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 
SQLInstall_strdup_multi(LPCSTR str)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 
SQLInstall_strdup(LPCSTR str)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  */
SQLInstall_narrow(int mode,LPSTR buffer,LPCWSTR str,WORD str_length,WORD buffer_length,WORD * returned_length)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 
SQLConfigDataSourceW(HWND hwndParent,WORD fRequest,LPCWSTR lpszDriver,LPCWSTR lpszAttributes)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 
SQLConfigDataSource(HWND hwndParent,WORD fRequest,LPCSTR lpszDriver,LPCSTR lpszAttributes)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 
load_config_driver(const WCHAR * driver)249 static HMODULE load_config_driver(const WCHAR *driver)
250 {
251     static WCHAR reg_driver[] = {'d','r','i','v','e','r',0};
252     long ret;
253     HMODULE hmod;
254     WCHAR *filename = NULL;
255     DWORD size = 0, type;
256     HKEY hkey;
257 
258     if ((ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey)) == ERROR_SUCCESS)
259     {
260         HKEY hkeydriver;
261 
262         if ((ret = RegOpenKeyW(hkey, driver, &hkeydriver)) == ERROR_SUCCESS)
263         {
264             ret = RegGetValueW(hkeydriver, NULL, reg_driver, RRF_RT_REG_SZ, &type, NULL, &size);
265             if(ret != ERROR_SUCCESS || type != REG_SZ)
266             {
267                 RegCloseKey(hkeydriver);
268                 RegCloseKey(hkey);
269                 push_error(ODBC_ERROR_INVALID_DSN, odbc_error_invalid_dsn);
270 
271                 return NULL;
272             }
273 
274             filename = HeapAlloc(GetProcessHeap(), 0, size);
275             if(!filename)
276             {
277                 RegCloseKey(hkeydriver);
278                 RegCloseKey(hkey);
279                 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
280 
281                 return NULL;
282             }
283             ret = RegGetValueW(hkeydriver, NULL, reg_driver, RRF_RT_REG_SZ, &type, filename, &size);
284 
285             RegCloseKey(hkeydriver);
286         }
287 
288         RegCloseKey(hkey);
289     }
290 
291     if(ret != ERROR_SUCCESS)
292     {
293         HeapFree(GetProcessHeap(), 0, filename);
294         push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
295         return NULL;
296     }
297 
298     hmod = LoadLibraryW(filename);
299     HeapFree(GetProcessHeap(), 0, filename);
300 
301     if(!hmod)
302         push_error(ODBC_ERROR_LOAD_LIB_FAILED, odbc_error_load_lib_failed);
303 
304     return hmod;
305 }
306 
write_config_value(const WCHAR * driver,const WCHAR * args)307 static BOOL write_config_value(const WCHAR *driver, const WCHAR *args)
308 {
309     long ret;
310     HKEY hkey, hkeydriver;
311     WCHAR *name = NULL;
312 
313     if(!args)
314         return FALSE;
315 
316     if((ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey)) == ERROR_SUCCESS)
317     {
318         if((ret = RegOpenKeyW(hkey, driver, &hkeydriver)) == ERROR_SUCCESS)
319         {
320             WCHAR *divider, *value;
321 
322             name = heap_alloc( (lstrlenW(args) + 1) * sizeof(WCHAR));
323             if(!name)
324             {
325                 push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
326                 goto fail;
327             }
328             lstrcpyW(name, args);
329 
330             divider = wcschr(name,'=');
331             if(!divider)
332             {
333                 push_error(ODBC_ERROR_INVALID_KEYWORD_VALUE, odbc_error_invalid_keyword);
334                 goto fail;
335             }
336 
337             value = divider + 1;
338             *divider = '\0';
339 
340             TRACE("Write pair: %s = %s\n", debugstr_w(name), debugstr_w(value));
341             if(RegSetValueExW(hkeydriver, name, 0, REG_SZ, (BYTE*)value,
342                                (lstrlenW(value)+1) * sizeof(WCHAR)) != ERROR_SUCCESS)
343                 ERR("Failed to write registry installed key\n");
344             heap_free(name);
345 
346             RegCloseKey(hkeydriver);
347         }
348 
349         RegCloseKey(hkey);
350     }
351 
352     if(ret != ERROR_SUCCESS)
353         push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
354 
355     return ret == ERROR_SUCCESS;
356 
357 fail:
358     RegCloseKey(hkeydriver);
359     RegCloseKey(hkey);
360     heap_free(name);
361 
362     return FALSE;
363 }
364 
SQLConfigDriverW(HWND hwnd,WORD request,LPCWSTR driver,LPCWSTR args,LPWSTR msg,WORD msgmax,WORD * msgout)365 BOOL WINAPI SQLConfigDriverW(HWND hwnd, WORD request, LPCWSTR driver,
366                LPCWSTR args, LPWSTR msg, WORD msgmax, WORD *msgout)
367 {
368     BOOL (WINAPI *pConfigDriverW)(HWND hwnd, WORD request, const WCHAR *driver, const WCHAR *args, const WCHAR *msg, WORD msgmax, WORD *msgout);
369     HMODULE hmod;
370     BOOL funcret = FALSE;
371 
372     clear_errors();
373     TRACE("(%p %d %s %s %p %d %p)\n", hwnd, request, debugstr_w(driver),
374           debugstr_w(args), msg, msgmax, msgout);
375 
376     if(request == ODBC_CONFIG_DRIVER)
377     {
378         return write_config_value(driver, args);
379     }
380 
381     hmod = load_config_driver(driver);
382     if(!hmod)
383         return FALSE;
384 
385     pConfigDriverW = (void*)GetProcAddress(hmod, "ConfigDriverW");
386     if(pConfigDriverW)
387         funcret = pConfigDriverW(hwnd, request, driver, args, msg, msgmax, msgout);
388 
389     if(!funcret)
390         push_error(ODBC_ERROR_REQUEST_FAILED, odbc_error_request_failed);
391 
392     FreeLibrary(hmod);
393 
394     return funcret;
395 }
396 
SQLConfigDriver(HWND hwnd,WORD request,LPCSTR driver,LPCSTR args,LPSTR msg,WORD msgmax,WORD * msgout)397 BOOL WINAPI SQLConfigDriver(HWND hwnd, WORD request, LPCSTR driver,
398                LPCSTR args, LPSTR msg, WORD msgmax, WORD *msgout)
399 {
400     BOOL (WINAPI *pConfigDriverA)(HWND hwnd, WORD request, const char *driver, const char *args, const char *msg, WORD msgmax, WORD *msgout);
401     HMODULE hmod;
402     WCHAR *driverW;
403     BOOL funcret = FALSE;
404 
405     clear_errors();
406     TRACE("(%p %d %s %s %p %d %p)\n", hwnd, request, debugstr_a(driver),
407           debugstr_a(args), msg, msgmax, msgout);
408 
409     driverW = heap_strdupAtoW(driver);
410     if(!driverW)
411     {
412         push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
413         return FALSE;
414     }
415     if(request == ODBC_CONFIG_DRIVER)
416     {
417         BOOL ret = FALSE;
418         WCHAR *argsW = heap_strdupAtoW(args);
419         if(argsW)
420         {
421             ret = write_config_value(driverW, argsW);
422             HeapFree(GetProcessHeap(), 0, argsW);
423         }
424         else
425         {
426             push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
427         }
428 
429         HeapFree(GetProcessHeap(), 0, driverW);
430 
431         return ret;
432     }
433 
434     hmod = load_config_driver(driverW);
435     HeapFree(GetProcessHeap(), 0, driverW);
436     if(!hmod)
437         return FALSE;
438 
439     pConfigDriverA = (void*)GetProcAddress(hmod, "ConfigDriver");
440     if(pConfigDriverA)
441         funcret = pConfigDriverA(hwnd, request, driver, args, msg, msgmax, msgout);
442 
443     if(!funcret)
444         push_error(ODBC_ERROR_REQUEST_FAILED, odbc_error_request_failed);
445 
446     FreeLibrary(hmod);
447 
448     return funcret;
449 }
450 
SQLCreateDataSourceW(HWND hwnd,LPCWSTR lpszDS)451 BOOL WINAPI SQLCreateDataSourceW(HWND hwnd, LPCWSTR lpszDS)
452 {
453     clear_errors();
454     FIXME("%p %s\n", hwnd, debugstr_w(lpszDS));
455     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
456     return FALSE;
457 }
458 
SQLCreateDataSource(HWND hwnd,LPCSTR lpszDS)459 BOOL WINAPI SQLCreateDataSource(HWND hwnd, LPCSTR lpszDS)
460 {
461     clear_errors();
462     FIXME("%p %s\n", hwnd, debugstr_a(lpszDS));
463     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
464     return FALSE;
465 }
466 
SQLGetAvailableDriversW(LPCWSTR lpszInfFile,LPWSTR lpszBuf,WORD cbBufMax,WORD * pcbBufOut)467 BOOL WINAPI SQLGetAvailableDriversW(LPCWSTR lpszInfFile, LPWSTR lpszBuf,
468                WORD cbBufMax, WORD *pcbBufOut)
469 {
470     clear_errors();
471     FIXME("%s %p %d %p\n", debugstr_w(lpszInfFile), lpszBuf, cbBufMax, pcbBufOut);
472     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
473     return FALSE;
474 }
475 
SQLGetAvailableDrivers(LPCSTR lpszInfFile,LPSTR lpszBuf,WORD cbBufMax,WORD * pcbBufOut)476 BOOL WINAPI SQLGetAvailableDrivers(LPCSTR lpszInfFile, LPSTR lpszBuf,
477                WORD cbBufMax, WORD *pcbBufOut)
478 {
479     clear_errors();
480     FIXME("%s %p %d %p\n", debugstr_a(lpszInfFile), lpszBuf, cbBufMax, pcbBufOut);
481     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
482     return FALSE;
483 }
484 
SQLGetConfigMode(UWORD * pwConfigMode)485 BOOL WINAPI SQLGetConfigMode(UWORD *pwConfigMode)
486 {
487     clear_errors();
488     TRACE("%p\n", pwConfigMode);
489     if (pwConfigMode)
490         *pwConfigMode = config_mode;
491     return TRUE;
492 }
493 
SQLGetInstalledDriversW(WCHAR * buf,WORD size,WORD * sizeout)494 BOOL WINAPI SQLGetInstalledDriversW(WCHAR *buf, WORD size, WORD *sizeout)
495 {
496     WORD written = 0;
497     DWORD index = 0;
498     BOOL ret = TRUE;
499     DWORD valuelen;
500     WCHAR *value;
501     HKEY drivers;
502     DWORD len;
503     LONG res;
504 
505     clear_errors();
506 
507     TRACE("%p %d %p\n", buf, size, sizeout);
508 
509     if (!buf || !size)
510     {
511         push_error(ODBC_ERROR_INVALID_BUFF_LEN, odbc_error_invalid_buff_len);
512         return FALSE;
513     }
514 
515     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, drivers_key, 0, KEY_QUERY_VALUE, &drivers);
516     if (res)
517     {
518         push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
519         return FALSE;
520     }
521 
522     valuelen = 256;
523     value = heap_alloc(valuelen * sizeof(WCHAR));
524 
525     size--;
526 
527     while (1)
528     {
529         len = valuelen;
530         res = RegEnumValueW(drivers, index, value, &len, NULL, NULL, NULL, NULL);
531         while (res == ERROR_MORE_DATA)
532         {
533             value = heap_realloc(value, ++len * sizeof(WCHAR));
534             res = RegEnumValueW(drivers, index, value, &len, NULL, NULL, NULL, NULL);
535         }
536         if (res == ERROR_SUCCESS)
537         {
538             lstrcpynW(buf + written, value, size - written);
539             written += min(len + 1, size - written);
540         }
541         else if (res == ERROR_NO_MORE_ITEMS)
542             break;
543         else
544         {
545             push_error(ODBC_ERROR_GENERAL_ERR, odbc_error_general_err);
546             ret = FALSE;
547             break;
548         }
549         index++;
550     }
551 
552     buf[written++] = 0;
553 
554     heap_free(value);
555     RegCloseKey(drivers);
556     if (sizeout)
557         *sizeout = written;
558     return ret;
559 }
560 
SQLGetInstalledDrivers(char * buf,WORD size,WORD * sizeout)561 BOOL WINAPI SQLGetInstalledDrivers(char *buf, WORD size, WORD *sizeout)
562 {
563     WORD written;
564     WCHAR *wbuf;
565     BOOL ret;
566 
567     TRACE("%p %d %p\n", buf, size, sizeout);
568 
569     if (!buf || !size)
570     {
571         push_error(ODBC_ERROR_INVALID_BUFF_LEN, odbc_error_invalid_buff_len);
572         return FALSE;
573     }
574 
575     wbuf = heap_alloc(size * sizeof(WCHAR));
576     if (!wbuf)
577     {
578         push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
579         return FALSE;
580     }
581 
582     ret = SQLGetInstalledDriversW(wbuf, size, &written);
583     if (!ret)
584     {
585         heap_free(wbuf);
586         return FALSE;
587     }
588 
589     *sizeout = WideCharToMultiByte(CP_ACP, 0, wbuf, written, NULL, 0, NULL, NULL);
590     WideCharToMultiByte(CP_ACP, 0, wbuf, written, buf, size, NULL, NULL);
591 
592     heap_free(wbuf);
593     return TRUE;
594 }
595 
get_privateprofile_sectionkey(LPCWSTR section,LPCWSTR filename)596 static HKEY get_privateprofile_sectionkey(LPCWSTR section, LPCWSTR filename)
597 {
598     HKEY hkey, hkeyfilename, hkeysection;
599     LONG ret;
600 
601     if (RegOpenKeyW(HKEY_CURRENT_USER, odbcW, &hkey))
602         return NULL;
603 
604     ret = RegOpenKeyW(hkey, filename, &hkeyfilename);
605     RegCloseKey(hkey);
606     if (ret)
607         return NULL;
608 
609     ret = RegOpenKeyW(hkeyfilename, section, &hkeysection);
610     RegCloseKey(hkeyfilename);
611 
612     return ret ? NULL : hkeysection;
613 }
614 
SQLGetPrivateProfileStringW(LPCWSTR section,LPCWSTR entry,LPCWSTR defvalue,LPWSTR buff,int buff_len,LPCWSTR filename)615 int WINAPI SQLGetPrivateProfileStringW(LPCWSTR section, LPCWSTR entry,
616     LPCWSTR defvalue, LPWSTR buff, int buff_len, LPCWSTR filename)
617 {
618     BOOL usedefault = TRUE;
619     HKEY sectionkey;
620     LONG ret = 0;
621 
622     TRACE("%s %s %s %p %d %s\n", debugstr_w(section), debugstr_w(entry),
623                debugstr_w(defvalue), buff, buff_len, debugstr_w(filename));
624 
625     clear_errors();
626 
627     if (buff_len <= 0 || !section)
628         return 0;
629 
630     if(buff)
631         buff[0] = 0;
632 
633     if (!defvalue || !buff)
634         return 0;
635 
636     sectionkey = get_privateprofile_sectionkey(section, filename);
637     if (sectionkey)
638     {
639         DWORD type, size;
640 
641         if (entry)
642         {
643             size = buff_len * sizeof(*buff);
644             if (RegGetValueW(sectionkey, NULL, entry, RRF_RT_REG_SZ, &type, buff, &size) == ERROR_SUCCESS)
645             {
646                 usedefault = FALSE;
647                 ret = (size / sizeof(*buff)) - 1;
648             }
649         }
650         else
651         {
652             WCHAR name[MAX_PATH];
653             DWORD index = 0;
654             DWORD namelen;
655 
656             usedefault = FALSE;
657 
658             memset(buff, 0, buff_len);
659 
660             namelen = sizeof(name);
661             while (RegEnumValueW(sectionkey, index, name, &namelen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
662             {
663                 if ((ret +  namelen+1) > buff_len)
664                     break;
665 
666                 lstrcpyW(buff+ret, name);
667                 ret += namelen+1;
668                 namelen = sizeof(name);
669                 index++;
670             }
671         }
672 
673         RegCloseKey(sectionkey);
674     }
675     else
676         usedefault = entry != NULL;
677 
678     if (usedefault)
679     {
680         lstrcpynW(buff, defvalue, buff_len);
681         ret = lstrlenW(buff);
682     }
683 
684     return ret;
685 }
686 
SQLGetPrivateProfileString(LPCSTR section,LPCSTR entry,LPCSTR defvalue,LPSTR buff,int buff_len,LPCSTR filename)687 int WINAPI SQLGetPrivateProfileString(LPCSTR section, LPCSTR entry,
688     LPCSTR defvalue, LPSTR buff, int buff_len, LPCSTR filename)
689 {
690     WCHAR *sectionW, *filenameW;
691     BOOL usedefault = TRUE;
692     HKEY sectionkey;
693     LONG ret = 0;
694 
695     TRACE("%s %s %s %p %d %s\n", debugstr_a(section), debugstr_a(entry),
696                debugstr_a(defvalue), buff, buff_len, debugstr_a(filename));
697 
698     clear_errors();
699 
700     if (buff_len <= 0)
701         return 0;
702 
703     if (buff)
704         buff[0] = 0;
705 
706     if (!section || !defvalue || !buff)
707         return 0;
708 
709     sectionW = heap_strdupAtoW(section);
710     filenameW = heap_strdupAtoW(filename);
711 
712     sectionkey = get_privateprofile_sectionkey(sectionW, filenameW);
713 
714     heap_free(sectionW);
715     heap_free(filenameW);
716 
717     if (sectionkey)
718     {
719         DWORD type, size;
720 
721         if (entry)
722         {
723             size = buff_len * sizeof(*buff);
724             if (RegGetValueA(sectionkey, NULL, entry, RRF_RT_REG_SZ, &type, buff, &size) == ERROR_SUCCESS)
725             {
726                 usedefault = FALSE;
727                 ret = (size / sizeof(*buff)) - 1;
728             }
729         }
730         else
731         {
732             char name[MAX_PATH] = {0};
733             DWORD index = 0;
734             DWORD namelen;
735 
736             usedefault = FALSE;
737 
738             memset(buff, 0, buff_len);
739 
740             namelen = sizeof(name);
741             while (RegEnumValueA(sectionkey, index, name, &namelen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
742             {
743                 if ((ret +  namelen+1) > buff_len)
744                     break;
745 
746                 lstrcpyA(buff+ret, name);
747 
748                 ret += namelen+1;
749                 namelen = sizeof(name);
750                 index++;
751             }
752         }
753 
754         RegCloseKey(sectionkey);
755     }
756     else
757         usedefault = entry != NULL;
758 
759     if (usedefault)
760     {
761         lstrcpynA(buff, defvalue, buff_len);
762         ret = strlen(buff);
763     }
764 
765     return ret;
766 }
767 
SQLGetTranslatorW(HWND hwndParent,LPWSTR lpszName,WORD cbNameMax,WORD * pcbNameOut,LPWSTR lpszPath,WORD cbPathMax,WORD * pcbPathOut,DWORD * pvOption)768 BOOL WINAPI SQLGetTranslatorW(HWND hwndParent, LPWSTR lpszName, WORD cbNameMax,
769                WORD *pcbNameOut, LPWSTR lpszPath, WORD cbPathMax,
770                WORD *pcbPathOut, DWORD *pvOption)
771 {
772     clear_errors();
773     FIXME("%p %s %d %p %p %d %p %p\n", hwndParent, debugstr_w(lpszName), cbNameMax,
774                pcbNameOut, lpszPath, cbPathMax, pcbPathOut, pvOption);
775     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
776     return FALSE;
777 }
778 
SQLGetTranslator(HWND hwndParent,LPSTR lpszName,WORD cbNameMax,WORD * pcbNameOut,LPSTR lpszPath,WORD cbPathMax,WORD * pcbPathOut,DWORD * pvOption)779 BOOL WINAPI SQLGetTranslator(HWND hwndParent, LPSTR lpszName, WORD cbNameMax,
780                WORD *pcbNameOut, LPSTR lpszPath, WORD cbPathMax,
781                WORD *pcbPathOut, DWORD *pvOption)
782 {
783     clear_errors();
784     FIXME("%p %s %d %p %p %d %p %p\n", hwndParent, debugstr_a(lpszName), cbNameMax,
785                pcbNameOut, lpszPath, cbPathMax, pcbPathOut, pvOption);
786     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
787     return FALSE;
788 }
789 
SQLInstallDriverW(LPCWSTR lpszInfFile,LPCWSTR lpszDriver,LPWSTR lpszPath,WORD cbPathMax,WORD * pcbPathOut)790 BOOL WINAPI SQLInstallDriverW(LPCWSTR lpszInfFile, LPCWSTR lpszDriver,
791                LPWSTR lpszPath, WORD cbPathMax, WORD * pcbPathOut)
792 {
793     DWORD usage;
794 
795     clear_errors();
796     TRACE("%s %s %p %d %p\n", debugstr_w(lpszInfFile),
797           debugstr_w(lpszDriver), lpszPath, cbPathMax, pcbPathOut);
798 
799     if (lpszInfFile)
800         return FALSE;
801 
802     return SQLInstallDriverExW(lpszDriver, NULL, lpszPath, cbPathMax,
803                                pcbPathOut, ODBC_INSTALL_COMPLETE, &usage);
804 }
805 
SQLInstallDriver(LPCSTR lpszInfFile,LPCSTR lpszDriver,LPSTR lpszPath,WORD cbPathMax,WORD * pcbPathOut)806 BOOL WINAPI SQLInstallDriver(LPCSTR lpszInfFile, LPCSTR lpszDriver,
807                LPSTR lpszPath, WORD cbPathMax, WORD * pcbPathOut)
808 {
809     DWORD usage;
810 
811     clear_errors();
812     TRACE("%s %s %p %d %p\n", debugstr_a(lpszInfFile),
813           debugstr_a(lpszDriver), lpszPath, cbPathMax, pcbPathOut);
814 
815     if (lpszInfFile)
816         return FALSE;
817 
818     return SQLInstallDriverEx(lpszDriver, NULL, lpszPath, cbPathMax,
819                               pcbPathOut, ODBC_INSTALL_COMPLETE, &usage);
820 }
821 
write_registry_values(const WCHAR * regkey,const WCHAR * driver,const WCHAR * path_in,WCHAR * path,DWORD * usage_count)822 static void write_registry_values(const WCHAR *regkey, const WCHAR *driver, const  WCHAR *path_in, WCHAR *path,
823                                   DWORD *usage_count)
824 {
825     static const WCHAR installed[] = {'I','n','s','t','a','l','l','e','d',0};
826     static const WCHAR slash[] = {'\\', 0};
827     static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
828     static const WCHAR setupW[] = {'S','e','t','u','p',0};
829     static const WCHAR translator[] = {'T','r','a','n','s','l','a','t','o','r',0};
830     HKEY hkey, hkeydriver;
831 
832     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey) == ERROR_SUCCESS)
833     {
834         if (RegCreateKeyW(hkey, regkey, &hkeydriver) == ERROR_SUCCESS)
835         {
836             if(RegSetValueExW(hkeydriver, driver, 0, REG_SZ, (BYTE*)installed, sizeof(installed)) != ERROR_SUCCESS)
837                 ERR("Failed to write registry installed key\n");
838 
839             RegCloseKey(hkeydriver);
840         }
841 
842         if (RegCreateKeyW(hkey, driver, &hkeydriver) == ERROR_SUCCESS)
843         {
844             WCHAR entry[1024];
845             const WCHAR *p;
846             DWORD usagecount = 0;
847             DWORD type, size;
848 
849             /* Skip name entry */
850             p = driver;
851             p += lstrlenW(p) + 1;
852 
853             if (!path_in)
854                 GetSystemDirectoryW(path, MAX_PATH);
855             else
856                 lstrcpyW(path, path_in);
857 
858             /* Store Usage */
859             size = sizeof(usagecount);
860             RegGetValueA(hkeydriver, NULL, "UsageCount", RRF_RT_DWORD, &type, &usagecount, &size);
861             TRACE("Usage count %d\n", usagecount);
862 
863             for (; *p; p += lstrlenW(p) + 1)
864             {
865                 WCHAR *divider = wcschr(p,'=');
866 
867                 if (divider)
868                 {
869                     WCHAR *value;
870                     int len;
871 
872                     /* Write pair values to the registry. */
873                     lstrcpynW(entry, p, divider - p + 1);
874 
875                     divider++;
876                     TRACE("Writing pair %s,%s\n", debugstr_w(entry), debugstr_w(divider));
877 
878                     /* Driver, Setup, Translator entries use the system path unless a path is specified. */
879                     if(lstrcmpiW(driverW, entry) == 0 || lstrcmpiW(setupW, entry) == 0 ||
880                        lstrcmpiW(translator, entry) == 0)
881                     {
882                         len = lstrlenW(path) + lstrlenW(slash) + lstrlenW(divider) + 1;
883                         value = heap_alloc(len * sizeof(WCHAR));
884                         if(!value)
885                         {
886                             ERR("Out of memory\n");
887                             return;
888                         }
889 
890                         lstrcpyW(value, path);
891                         lstrcatW(value, slash);
892                         lstrcatW(value, divider);
893                     }
894                     else
895                     {
896                         len = lstrlenW(divider) + 1;
897                         value = heap_alloc(len * sizeof(WCHAR));
898                         lstrcpyW(value, divider);
899                     }
900 
901                     if (RegSetValueExW(hkeydriver, entry, 0, REG_SZ, (BYTE*)value,
902                                     (lstrlenW(value)+1)*sizeof(WCHAR)) != ERROR_SUCCESS)
903                         ERR("Failed to write registry data %s %s\n", debugstr_w(entry), debugstr_w(value));
904                     heap_free(value);
905                 }
906                 else
907                 {
908                     ERR("No pair found. %s\n", debugstr_w(p));
909                     break;
910                 }
911             }
912 
913             /* Set Usage Count */
914             usagecount++;
915             if (RegSetValueExA(hkeydriver, "UsageCount", 0, REG_DWORD, (BYTE*)&usagecount, sizeof(usagecount)) != ERROR_SUCCESS)
916                 ERR("Failed to write registry UsageCount key\n");
917 
918             if (usage_count)
919                 *usage_count = usagecount;
920 
921             RegCloseKey(hkeydriver);
922         }
923 
924         RegCloseKey(hkey);
925     }
926 }
927 
SQLInstallDriverExW(LPCWSTR lpszDriver,LPCWSTR lpszPathIn,LPWSTR lpszPathOut,WORD cbPathOutMax,WORD * pcbPathOut,WORD fRequest,LPDWORD lpdwUsageCount)928 BOOL WINAPI SQLInstallDriverExW(LPCWSTR lpszDriver, LPCWSTR lpszPathIn,
929                LPWSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
930                WORD fRequest, LPDWORD lpdwUsageCount)
931 {
932     UINT len;
933     WCHAR path[MAX_PATH];
934 
935     clear_errors();
936     TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszDriver),
937           debugstr_w(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
938           fRequest, lpdwUsageCount);
939 
940     write_registry_values(odbcdrivers, lpszDriver, lpszPathIn, path, lpdwUsageCount);
941 
942     len = lstrlenW(path);
943 
944     if (pcbPathOut)
945         *pcbPathOut = len;
946 
947     if (lpszPathOut && cbPathOutMax > len)
948     {
949         lstrcpyW(lpszPathOut, path);
950         return TRUE;
951     }
952     return FALSE;
953 }
954 
SQLInstallDriverEx(LPCSTR lpszDriver,LPCSTR lpszPathIn,LPSTR lpszPathOut,WORD cbPathOutMax,WORD * pcbPathOut,WORD fRequest,LPDWORD lpdwUsageCount)955 BOOL WINAPI SQLInstallDriverEx(LPCSTR lpszDriver, LPCSTR lpszPathIn,
956                LPSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
957                WORD fRequest, LPDWORD lpdwUsageCount)
958 {
959     LPWSTR driver, pathin;
960     WCHAR pathout[MAX_PATH];
961     BOOL ret;
962     WORD cbOut = 0;
963 
964     clear_errors();
965     TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszDriver),
966           debugstr_a(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
967           fRequest, lpdwUsageCount);
968 
969     driver = SQLInstall_strdup_multi(lpszDriver);
970     pathin = SQLInstall_strdup(lpszPathIn);
971 
972     ret = SQLInstallDriverExW(driver, pathin, pathout, MAX_PATH, &cbOut,
973                               fRequest, lpdwUsageCount);
974     if (ret)
975     {
976         int len =  WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
977                                        0, NULL, NULL);
978         if (len)
979         {
980             if (pcbPathOut)
981                 *pcbPathOut = len - 1;
982 
983             if (!lpszPathOut || cbPathOutMax < len)
984             {
985                 ret = FALSE;
986                 goto out;
987             }
988             len =  WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
989                                        cbPathOutMax, NULL, NULL);
990         }
991     }
992 
993 out:
994     HeapFree(GetProcessHeap(), 0, driver);
995     HeapFree(GetProcessHeap(), 0, pathin);
996     return ret;
997 }
998 
SQLInstallDriverManagerW(LPWSTR lpszPath,WORD cbPathMax,WORD * pcbPathOut)999 BOOL WINAPI SQLInstallDriverManagerW(LPWSTR lpszPath, WORD cbPathMax,
1000                WORD *pcbPathOut)
1001 {
1002     UINT len;
1003     WCHAR path[MAX_PATH];
1004 
1005     TRACE("(%p %d %p)\n", lpszPath, cbPathMax, pcbPathOut);
1006 
1007     if (cbPathMax < MAX_PATH)
1008         return FALSE;
1009 
1010     clear_errors();
1011 
1012     len = GetSystemDirectoryW(path, MAX_PATH);
1013 
1014     if (pcbPathOut)
1015         *pcbPathOut = len;
1016 
1017     if (lpszPath && cbPathMax > len)
1018     {
1019     	lstrcpyW(lpszPath, path);
1020     	return TRUE;
1021     }
1022     return FALSE;
1023 }
1024 
SQLInstallDriverManager(LPSTR lpszPath,WORD cbPathMax,WORD * pcbPathOut)1025 BOOL WINAPI SQLInstallDriverManager(LPSTR lpszPath, WORD cbPathMax,
1026                WORD *pcbPathOut)
1027 {
1028     BOOL ret;
1029     WORD len, cbOut = 0;
1030     WCHAR path[MAX_PATH];
1031 
1032     TRACE("(%p %d %p)\n", lpszPath, cbPathMax, pcbPathOut);
1033 
1034     if (cbPathMax < MAX_PATH)
1035         return FALSE;
1036 
1037     clear_errors();
1038 
1039     ret = SQLInstallDriverManagerW(path, MAX_PATH, &cbOut);
1040     if (ret)
1041     {
1042         len =  WideCharToMultiByte(CP_ACP, 0, path, -1, lpszPath, 0,
1043                                    NULL, NULL);
1044         if (len)
1045         {
1046             if (pcbPathOut)
1047                 *pcbPathOut = len - 1;
1048 
1049             if (!lpszPath || cbPathMax < len)
1050                 return FALSE;
1051 
1052             len =  WideCharToMultiByte(CP_ACP, 0, path, -1, lpszPath,
1053                                        cbPathMax, NULL, NULL);
1054         }
1055     }
1056     return ret;
1057 }
1058 
SQLInstallODBCW(HWND hwndParent,LPCWSTR lpszInfFile,LPCWSTR lpszSrcPath,LPCWSTR lpszDrivers)1059 BOOL WINAPI SQLInstallODBCW(HWND hwndParent, LPCWSTR lpszInfFile,
1060                LPCWSTR lpszSrcPath, LPCWSTR lpszDrivers)
1061 {
1062     clear_errors();
1063     FIXME("%p %s %s %s\n", hwndParent, debugstr_w(lpszInfFile),
1064                debugstr_w(lpszSrcPath), debugstr_w(lpszDrivers));
1065     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1066     return FALSE;
1067 }
1068 
SQLInstallODBC(HWND hwndParent,LPCSTR lpszInfFile,LPCSTR lpszSrcPath,LPCSTR lpszDrivers)1069 BOOL WINAPI SQLInstallODBC(HWND hwndParent, LPCSTR lpszInfFile,
1070                LPCSTR lpszSrcPath, LPCSTR lpszDrivers)
1071 {
1072     clear_errors();
1073     FIXME("%p %s %s %s\n", hwndParent, debugstr_a(lpszInfFile),
1074                debugstr_a(lpszSrcPath), debugstr_a(lpszDrivers));
1075     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1076     return FALSE;
1077 }
1078 
SQLInstallerErrorW(WORD iError,DWORD * pfErrorCode,LPWSTR lpszErrorMsg,WORD cbErrorMsgMax,WORD * pcbErrorMsg)1079 SQLRETURN WINAPI SQLInstallerErrorW(WORD iError, DWORD *pfErrorCode,
1080                LPWSTR lpszErrorMsg, WORD cbErrorMsgMax, WORD *pcbErrorMsg)
1081 {
1082     TRACE("%d %p %p %d %p\n", iError, pfErrorCode, lpszErrorMsg,
1083           cbErrorMsgMax, pcbErrorMsg);
1084 
1085     if (iError == 0)
1086     {
1087         return SQL_ERROR;
1088     }
1089     else if (iError <= num_errors)
1090     {
1091         BOOL truncated = FALSE;
1092         WORD len;
1093         LPCWSTR msg;
1094         iError--;
1095         if (pfErrorCode)
1096             *pfErrorCode = error_code[iError];
1097         msg = error_msg[iError];
1098         len = msg ? lstrlenW(msg) : 0;
1099         if (pcbErrorMsg)
1100             *pcbErrorMsg = len;
1101         len++;
1102         if (cbErrorMsgMax < len)
1103         {
1104             len = cbErrorMsgMax;
1105             truncated = TRUE;
1106         }
1107         if (lpszErrorMsg && len)
1108         {
1109             if (msg)
1110             {
1111                 memcpy (lpszErrorMsg, msg, len * sizeof(WCHAR));
1112             }
1113             else
1114             {
1115                 assert(len==1);
1116                 *lpszErrorMsg = 0;
1117             }
1118         }
1119         else
1120         {
1121             /* Yes.  If you pass a null pointer and a large length it is not an error! */
1122             truncated = TRUE;
1123         }
1124 
1125         return truncated ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
1126     }
1127 
1128     /* 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 */
1129     if (pcbErrorMsg)
1130         *pcbErrorMsg = 0;
1131 
1132     if (lpszErrorMsg && cbErrorMsgMax > 0)
1133         *lpszErrorMsg = '\0';
1134 
1135     return SQL_NO_DATA;
1136 }
1137 
SQLInstallerError(WORD iError,DWORD * pfErrorCode,LPSTR lpszErrorMsg,WORD cbErrorMsgMax,WORD * pcbErrorMsg)1138 SQLRETURN WINAPI SQLInstallerError(WORD iError, DWORD *pfErrorCode,
1139                LPSTR lpszErrorMsg, WORD cbErrorMsgMax, WORD *pcbErrorMsg)
1140 {
1141     SQLRETURN ret;
1142     LPWSTR wbuf;
1143     WORD cbwbuf;
1144     TRACE("%d %p %p %d %p\n", iError, pfErrorCode, lpszErrorMsg,
1145           cbErrorMsgMax, pcbErrorMsg);
1146 
1147     wbuf = 0;
1148     if (lpszErrorMsg && cbErrorMsgMax)
1149     {
1150         wbuf = HeapAlloc(GetProcessHeap(), 0, cbErrorMsgMax*sizeof(WCHAR));
1151         if (!wbuf)
1152             return SQL_ERROR;
1153     }
1154     ret = SQLInstallerErrorW(iError, pfErrorCode, wbuf, cbErrorMsgMax, &cbwbuf);
1155     if (wbuf)
1156     {
1157         WORD cbBuf = 0;
1158         SQLInstall_narrow(1, lpszErrorMsg, wbuf, cbwbuf+1, cbErrorMsgMax, &cbBuf);
1159         HeapFree(GetProcessHeap(), 0, wbuf);
1160         if (pcbErrorMsg)
1161             *pcbErrorMsg = cbBuf-1;
1162     }
1163     return ret;
1164 }
1165 
SQLInstallTranslatorExW(LPCWSTR lpszTranslator,LPCWSTR lpszPathIn,LPWSTR lpszPathOut,WORD cbPathOutMax,WORD * pcbPathOut,WORD fRequest,LPDWORD lpdwUsageCount)1166 BOOL WINAPI SQLInstallTranslatorExW(LPCWSTR lpszTranslator, LPCWSTR lpszPathIn,
1167                LPWSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
1168                WORD fRequest, LPDWORD lpdwUsageCount)
1169 {
1170     UINT len;
1171     WCHAR path[MAX_PATH];
1172 
1173     clear_errors();
1174     TRACE("%s %s %p %d %p %d %p\n", debugstr_w(lpszTranslator),
1175           debugstr_w(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
1176           fRequest, lpdwUsageCount);
1177 
1178     write_registry_values(odbctranslators, lpszTranslator, lpszPathIn, path, lpdwUsageCount);
1179 
1180     len = lstrlenW(path);
1181 
1182     if (pcbPathOut)
1183         *pcbPathOut = len;
1184 
1185     if (lpszPathOut && cbPathOutMax > len)
1186     {
1187         lstrcpyW(lpszPathOut, path);
1188         return TRUE;
1189     }
1190     return FALSE;
1191 }
1192 
SQLInstallTranslatorEx(LPCSTR lpszTranslator,LPCSTR lpszPathIn,LPSTR lpszPathOut,WORD cbPathOutMax,WORD * pcbPathOut,WORD fRequest,LPDWORD lpdwUsageCount)1193 BOOL WINAPI SQLInstallTranslatorEx(LPCSTR lpszTranslator, LPCSTR lpszPathIn,
1194                LPSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut,
1195                WORD fRequest, LPDWORD lpdwUsageCount)
1196 {
1197     LPCSTR p;
1198     LPWSTR translator, pathin;
1199     WCHAR pathout[MAX_PATH];
1200     BOOL ret;
1201     WORD cbOut = 0;
1202 
1203     clear_errors();
1204     TRACE("%s %s %p %d %p %d %p\n", debugstr_a(lpszTranslator),
1205           debugstr_a(lpszPathIn), lpszPathOut, cbPathOutMax, pcbPathOut,
1206           fRequest, lpdwUsageCount);
1207 
1208     for (p = lpszTranslator; *p; p += lstrlenA(p) + 1)
1209         TRACE("%s\n", debugstr_a(p));
1210 
1211     translator = SQLInstall_strdup_multi(lpszTranslator);
1212     pathin = SQLInstall_strdup(lpszPathIn);
1213 
1214     ret = SQLInstallTranslatorExW(translator, pathin, pathout, MAX_PATH,
1215                                   &cbOut, fRequest, lpdwUsageCount);
1216     if (ret)
1217     {
1218         int len =  WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
1219                                        0, NULL, NULL);
1220         if (len)
1221         {
1222             if (pcbPathOut)
1223                 *pcbPathOut = len - 1;
1224 
1225             if (!lpszPathOut || cbPathOutMax < len)
1226             {
1227                 ret = FALSE;
1228                 goto out;
1229             }
1230             len =  WideCharToMultiByte(CP_ACP, 0, pathout, -1, lpszPathOut,
1231                                        cbPathOutMax, NULL, NULL);
1232         }
1233     }
1234 
1235 out:
1236     HeapFree(GetProcessHeap(), 0, translator);
1237     HeapFree(GetProcessHeap(), 0, pathin);
1238     return ret;
1239 }
1240 
SQLInstallTranslator(LPCSTR lpszInfFile,LPCSTR lpszTranslator,LPCSTR lpszPathIn,LPSTR lpszPathOut,WORD cbPathOutMax,WORD * pcbPathOut,WORD fRequest,LPDWORD lpdwUsageCount)1241 BOOL WINAPI SQLInstallTranslator(LPCSTR lpszInfFile, LPCSTR lpszTranslator,
1242                LPCSTR lpszPathIn, LPSTR lpszPathOut, WORD cbPathOutMax,
1243                WORD *pcbPathOut, WORD fRequest, LPDWORD lpdwUsageCount)
1244 {
1245     clear_errors();
1246     TRACE("%s %s %s %p %d %p %d %p\n", debugstr_a(lpszInfFile),
1247           debugstr_a(lpszTranslator), debugstr_a(lpszPathIn), lpszPathOut,
1248           cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
1249 
1250     if (lpszInfFile)
1251         return FALSE;
1252 
1253     return SQLInstallTranslatorEx(lpszTranslator, lpszPathIn, lpszPathOut,
1254                        cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
1255 }
1256 
SQLInstallTranslatorW(LPCWSTR lpszInfFile,LPCWSTR lpszTranslator,LPCWSTR lpszPathIn,LPWSTR lpszPathOut,WORD cbPathOutMax,WORD * pcbPathOut,WORD fRequest,LPDWORD lpdwUsageCount)1257 BOOL WINAPI SQLInstallTranslatorW(LPCWSTR lpszInfFile, LPCWSTR lpszTranslator,
1258               LPCWSTR lpszPathIn, LPWSTR lpszPathOut, WORD cbPathOutMax,
1259               WORD *pcbPathOut, WORD fRequest, LPDWORD lpdwUsageCount)
1260 {
1261     clear_errors();
1262     TRACE("%s %s %s %p %d %p %d %p\n", debugstr_w(lpszInfFile),
1263           debugstr_w(lpszTranslator), debugstr_w(lpszPathIn), lpszPathOut,
1264           cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
1265 
1266     if (lpszInfFile)
1267         return FALSE;
1268 
1269     return SQLInstallTranslatorExW(lpszTranslator, lpszPathIn, lpszPathOut,
1270                         cbPathOutMax, pcbPathOut, fRequest, lpdwUsageCount);
1271 }
1272 
SQLManageDataSources(HWND hwnd)1273 BOOL WINAPI SQLManageDataSources(HWND hwnd)
1274 {
1275     clear_errors();
1276     FIXME("%p\n", hwnd);
1277     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1278     return FALSE;
1279 }
1280 
SQLPostInstallerErrorW(DWORD fErrorCode,LPCWSTR szErrorMsg)1281 SQLRETURN WINAPI SQLPostInstallerErrorW(DWORD fErrorCode, LPCWSTR szErrorMsg)
1282 {
1283     FIXME("%u %s\n", fErrorCode, debugstr_w(szErrorMsg));
1284     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1285     return FALSE;
1286 }
1287 
SQLPostInstallerError(DWORD fErrorCode,LPCSTR szErrorMsg)1288 SQLRETURN WINAPI SQLPostInstallerError(DWORD fErrorCode, LPCSTR szErrorMsg)
1289 {
1290     FIXME("%u %s\n", fErrorCode, debugstr_a(szErrorMsg));
1291     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1292     return FALSE;
1293 }
1294 
SQLReadFileDSNW(LPCWSTR lpszFileName,LPCWSTR lpszAppName,LPCWSTR lpszKeyName,LPWSTR lpszString,WORD cbString,WORD * pcbString)1295 BOOL WINAPI SQLReadFileDSNW(LPCWSTR lpszFileName, LPCWSTR lpszAppName,
1296                LPCWSTR lpszKeyName, LPWSTR lpszString, WORD cbString,
1297                WORD *pcbString)
1298 {
1299     clear_errors();
1300     FIXME("%s %s %s %s %d %p\n", debugstr_w(lpszFileName), debugstr_w(lpszAppName),
1301                debugstr_w(lpszKeyName), debugstr_w(lpszString), cbString, pcbString);
1302     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1303     return FALSE;
1304 }
1305 
SQLReadFileDSN(LPCSTR lpszFileName,LPCSTR lpszAppName,LPCSTR lpszKeyName,LPSTR lpszString,WORD cbString,WORD * pcbString)1306 BOOL WINAPI SQLReadFileDSN(LPCSTR lpszFileName, LPCSTR lpszAppName,
1307                LPCSTR lpszKeyName, LPSTR lpszString, WORD cbString,
1308                WORD *pcbString)
1309 {
1310     clear_errors();
1311     FIXME("%s %s %s %s %d %p\n", debugstr_a(lpszFileName), debugstr_a(lpszAppName),
1312                debugstr_a(lpszKeyName), debugstr_a(lpszString), cbString, pcbString);
1313     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1314     return FALSE;
1315 }
1316 
SQLRemoveDefaultDataSource(void)1317 BOOL WINAPI SQLRemoveDefaultDataSource(void)
1318 {
1319     clear_errors();
1320     FIXME("\n");
1321     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1322     return FALSE;
1323 }
1324 
SQLRemoveDriverW(LPCWSTR drivername,BOOL remove_dsn,LPDWORD usage_count)1325 BOOL WINAPI SQLRemoveDriverW(LPCWSTR drivername, BOOL remove_dsn, LPDWORD usage_count)
1326 {
1327     HKEY hkey;
1328     DWORD usagecount = 1;
1329 
1330     clear_errors();
1331     TRACE("%s %d %p\n", debugstr_w(drivername), remove_dsn, usage_count);
1332 
1333     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey) == ERROR_SUCCESS)
1334     {
1335         HKEY hkeydriver;
1336 
1337         if (RegOpenKeyW(hkey, drivername, &hkeydriver) == ERROR_SUCCESS)
1338         {
1339             DWORD size, type;
1340             DWORD count;
1341 
1342             size = sizeof(usagecount);
1343             RegGetValueA(hkeydriver, NULL, "UsageCount", RRF_RT_DWORD, &type, &usagecount, &size);
1344             TRACE("Usage count %d\n", usagecount);
1345             count = usagecount - 1;
1346             if (count)
1347             {
1348                  if (RegSetValueExA(hkeydriver, "UsageCount", 0, REG_DWORD, (BYTE*)&count, sizeof(count)) != ERROR_SUCCESS)
1349                     ERR("Failed to write registry UsageCount key\n");
1350             }
1351 
1352             RegCloseKey(hkeydriver);
1353         }
1354 
1355         if (usagecount)
1356             usagecount--;
1357 
1358         if (!usagecount)
1359         {
1360             if (RegDeleteKeyW(hkey, drivername) != ERROR_SUCCESS)
1361                 ERR("Failed to delete registry key: %s\n", debugstr_w(drivername));
1362 
1363             if (RegOpenKeyW(hkey, odbcdrivers, &hkeydriver) == ERROR_SUCCESS)
1364             {
1365                 if(RegDeleteValueW(hkeydriver, drivername) != ERROR_SUCCESS)
1366                     ERR("Failed to delete registry value: %s\n", debugstr_w(drivername));
1367                 RegCloseKey(hkeydriver);
1368             }
1369         }
1370 
1371         RegCloseKey(hkey);
1372     }
1373 
1374     if (usage_count)
1375         *usage_count = usagecount;
1376 
1377     return TRUE;
1378 }
1379 
SQLRemoveDriver(LPCSTR lpszDriver,BOOL fRemoveDSN,LPDWORD lpdwUsageCount)1380 BOOL WINAPI SQLRemoveDriver(LPCSTR lpszDriver, BOOL fRemoveDSN,
1381                LPDWORD lpdwUsageCount)
1382 {
1383     WCHAR *driver;
1384     BOOL ret;
1385 
1386     clear_errors();
1387     TRACE("%s %d %p\n", debugstr_a(lpszDriver), fRemoveDSN, lpdwUsageCount);
1388 
1389     driver = SQLInstall_strdup(lpszDriver);
1390 
1391     ret =  SQLRemoveDriverW(driver, fRemoveDSN, lpdwUsageCount);
1392 
1393     HeapFree(GetProcessHeap(), 0, driver);
1394     return ret;
1395 }
1396 
SQLRemoveDriverManager(LPDWORD pdwUsageCount)1397 BOOL WINAPI SQLRemoveDriverManager(LPDWORD pdwUsageCount)
1398 {
1399     clear_errors();
1400     FIXME("%p\n", pdwUsageCount);
1401     if (pdwUsageCount) *pdwUsageCount = 1;
1402     return TRUE;
1403 }
1404 
SQLRemoveDSNFromIniW(LPCWSTR lpszDSN)1405 BOOL WINAPI SQLRemoveDSNFromIniW(LPCWSTR lpszDSN)
1406 {
1407     clear_errors();
1408     FIXME("%s\n", debugstr_w(lpszDSN));
1409     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1410     return FALSE;
1411 }
1412 
SQLRemoveDSNFromIni(LPCSTR lpszDSN)1413 BOOL WINAPI SQLRemoveDSNFromIni(LPCSTR lpszDSN)
1414 {
1415     clear_errors();
1416     FIXME("%s\n", debugstr_a(lpszDSN));
1417     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1418     return FALSE;
1419 }
1420 
SQLRemoveTranslatorW(const WCHAR * translator,DWORD * usage_count)1421 BOOL WINAPI SQLRemoveTranslatorW(const WCHAR *translator, DWORD *usage_count)
1422 {
1423     HKEY hkey;
1424     DWORD usagecount = 1;
1425     BOOL ret = TRUE;
1426 
1427     clear_errors();
1428     TRACE("%s %p\n", debugstr_w(translator), usage_count);
1429 
1430     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey) == ERROR_SUCCESS)
1431     {
1432         HKEY hkeydriver;
1433 
1434         if (RegOpenKeyW(hkey, translator, &hkeydriver) == ERROR_SUCCESS)
1435         {
1436             DWORD size, type;
1437             DWORD count;
1438 
1439             size = sizeof(usagecount);
1440             RegGetValueA(hkeydriver, NULL, "UsageCount", RRF_RT_DWORD, &type, &usagecount, &size);
1441             TRACE("Usage count %d\n", usagecount);
1442             count = usagecount - 1;
1443             if (count)
1444             {
1445                  if (RegSetValueExA(hkeydriver, "UsageCount", 0, REG_DWORD, (BYTE*)&count, sizeof(count)) != ERROR_SUCCESS)
1446                     ERR("Failed to write registry UsageCount key\n");
1447             }
1448 
1449             RegCloseKey(hkeydriver);
1450         }
1451 
1452         if (usagecount)
1453             usagecount--;
1454 
1455         if (!usagecount)
1456         {
1457             if(RegDeleteKeyW(hkey, translator) != ERROR_SUCCESS)
1458             {
1459                 push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
1460                 WARN("Failed to delete registry key: %s\n", debugstr_w(translator));
1461                 ret = FALSE;
1462             }
1463 
1464             if (ret && RegOpenKeyW(hkey, odbctranslators, &hkeydriver) == ERROR_SUCCESS)
1465             {
1466                 if(RegDeleteValueW(hkeydriver, translator) != ERROR_SUCCESS)
1467                 {
1468                     push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
1469                     WARN("Failed to delete registry key: %s\n", debugstr_w(translator));
1470                     ret = FALSE;
1471                 }
1472 
1473                 RegCloseKey(hkeydriver);
1474             }
1475         }
1476 
1477         RegCloseKey(hkey);
1478     }
1479 
1480     if (ret && usage_count)
1481         *usage_count = usagecount;
1482 
1483     return ret;
1484 }
1485 
SQLRemoveTranslator(LPCSTR lpszTranslator,LPDWORD lpdwUsageCount)1486 BOOL WINAPI SQLRemoveTranslator(LPCSTR lpszTranslator, LPDWORD lpdwUsageCount)
1487 {
1488     WCHAR *translator;
1489     BOOL ret;
1490 
1491     clear_errors();
1492     TRACE("%s %p\n", debugstr_a(lpszTranslator), lpdwUsageCount);
1493 
1494     translator = SQLInstall_strdup(lpszTranslator);
1495     ret =  SQLRemoveTranslatorW(translator, lpdwUsageCount);
1496 
1497     HeapFree(GetProcessHeap(), 0, translator);
1498     return ret;
1499 }
1500 
SQLSetConfigMode(UWORD wConfigMode)1501 BOOL WINAPI SQLSetConfigMode(UWORD wConfigMode)
1502 {
1503     clear_errors();
1504     TRACE("%u\n", wConfigMode);
1505 
1506     if (wConfigMode > ODBC_SYSTEM_DSN)
1507     {
1508         push_error(ODBC_ERROR_INVALID_PARAM_SEQUENCE, odbc_error_invalid_param_sequence);
1509         return FALSE;
1510     }
1511     else
1512     {
1513         config_mode = wConfigMode;
1514         return TRUE;
1515     }
1516 }
1517 
SQLValidDSNW(LPCWSTR lpszDSN)1518 BOOL WINAPI SQLValidDSNW(LPCWSTR lpszDSN)
1519 {
1520     static const WCHAR invalid[] = {'[',']','{','}','(',')',',',';','?','*','=','!','@','\\',0};
1521     clear_errors();
1522     TRACE("%s\n", debugstr_w(lpszDSN));
1523 
1524     if(lstrlenW(lpszDSN) > SQL_MAX_DSN_LENGTH || wcspbrk(lpszDSN, invalid) != NULL)
1525     {
1526         return FALSE;
1527     }
1528 
1529     return TRUE;
1530 }
1531 
SQLValidDSN(LPCSTR lpszDSN)1532 BOOL WINAPI SQLValidDSN(LPCSTR lpszDSN)
1533 {
1534     static const char *invalid = "[]{}(),;?*=!@\\";
1535     clear_errors();
1536     TRACE("%s\n", debugstr_a(lpszDSN));
1537 
1538     if(strlen(lpszDSN) > SQL_MAX_DSN_LENGTH || strpbrk(lpszDSN, invalid) != NULL)
1539     {
1540         return FALSE;
1541     }
1542 
1543     return TRUE;
1544 }
1545 
SQLWriteDSNToIniW(LPCWSTR lpszDSN,LPCWSTR lpszDriver)1546 BOOL WINAPI SQLWriteDSNToIniW(LPCWSTR lpszDSN, LPCWSTR lpszDriver)
1547 {
1548     clear_errors();
1549     FIXME("%s %s\n", debugstr_w(lpszDSN), debugstr_w(lpszDriver));
1550     return TRUE;
1551 }
1552 
SQLWriteDSNToIni(LPCSTR lpszDSN,LPCSTR lpszDriver)1553 BOOL WINAPI SQLWriteDSNToIni(LPCSTR lpszDSN, LPCSTR lpszDriver)
1554 {
1555     clear_errors();
1556     FIXME("%s %s\n", debugstr_a(lpszDSN), debugstr_a(lpszDriver));
1557     return TRUE;
1558 }
1559 
SQLWriteFileDSNW(LPCWSTR lpszFileName,LPCWSTR lpszAppName,LPCWSTR lpszKeyName,LPCWSTR lpszString)1560 BOOL WINAPI SQLWriteFileDSNW(LPCWSTR lpszFileName, LPCWSTR lpszAppName,
1561                LPCWSTR lpszKeyName, LPCWSTR lpszString)
1562 {
1563     clear_errors();
1564     FIXME("%s %s %s %s\n", debugstr_w(lpszFileName), debugstr_w(lpszAppName),
1565                  debugstr_w(lpszKeyName), debugstr_w(lpszString));
1566     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1567     return FALSE;
1568 }
1569 
SQLWriteFileDSN(LPCSTR lpszFileName,LPCSTR lpszAppName,LPCSTR lpszKeyName,LPCSTR lpszString)1570 BOOL WINAPI SQLWriteFileDSN(LPCSTR lpszFileName, LPCSTR lpszAppName,
1571                LPCSTR lpszKeyName, LPCSTR lpszString)
1572 {
1573     clear_errors();
1574     FIXME("%s %s %s %s\n", debugstr_a(lpszFileName), debugstr_a(lpszAppName),
1575                  debugstr_a(lpszKeyName), debugstr_a(lpszString));
1576     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1577     return FALSE;
1578 }
1579 
SQLWritePrivateProfileStringW(LPCWSTR lpszSection,LPCWSTR lpszEntry,LPCWSTR lpszString,LPCWSTR lpszFilename)1580 BOOL WINAPI SQLWritePrivateProfileStringW(LPCWSTR lpszSection, LPCWSTR lpszEntry,
1581                LPCWSTR lpszString, LPCWSTR lpszFilename)
1582 {
1583     static const WCHAR empty[] = {0};
1584     LONG ret;
1585     HKEY hkey;
1586 
1587     clear_errors();
1588     TRACE("%s %s %s %s\n", debugstr_w(lpszSection), debugstr_w(lpszEntry),
1589                 debugstr_w(lpszString), debugstr_w(lpszFilename));
1590 
1591     if(!lpszFilename || !*lpszFilename)
1592     {
1593         push_error(ODBC_ERROR_INVALID_STR, odbc_error_invalid_param_string);
1594         return FALSE;
1595     }
1596 
1597     if ((ret = RegCreateKeyW(HKEY_CURRENT_USER, odbcW, &hkey)) == ERROR_SUCCESS)
1598     {
1599          HKEY hkeyfilename;
1600 
1601          if ((ret = RegCreateKeyW(hkey, lpszFilename, &hkeyfilename)) == ERROR_SUCCESS)
1602          {
1603               HKEY hkey_section;
1604 
1605               if ((ret = RegCreateKeyW(hkeyfilename, lpszSection, &hkey_section)) == ERROR_SUCCESS)
1606               {
1607                   if(lpszString)
1608                       ret = RegSetValueExW(hkey_section, lpszEntry, 0, REG_SZ, (BYTE*)lpszString, (lstrlenW(lpszString)+1)*sizeof(WCHAR));
1609                   else
1610                       ret = RegSetValueExW(hkey_section, lpszEntry, 0, REG_SZ, (BYTE*)empty, sizeof(empty));
1611                   RegCloseKey(hkey_section);
1612               }
1613 
1614               RegCloseKey(hkeyfilename);
1615          }
1616 
1617          RegCloseKey(hkey);
1618     }
1619 
1620     return ret == ERROR_SUCCESS;
1621 }
1622 
SQLWritePrivateProfileString(LPCSTR lpszSection,LPCSTR lpszEntry,LPCSTR lpszString,LPCSTR lpszFilename)1623 BOOL WINAPI SQLWritePrivateProfileString(LPCSTR lpszSection, LPCSTR lpszEntry,
1624                LPCSTR lpszString, LPCSTR lpszFilename)
1625 {
1626     BOOL ret;
1627     WCHAR *sect, *entry, *string, *file;
1628     clear_errors();
1629     TRACE("%s %s %s %s\n", lpszSection, lpszEntry, lpszString, lpszFilename);
1630 
1631     sect = heap_strdupAtoW(lpszSection);
1632     entry = heap_strdupAtoW(lpszEntry);
1633     string = heap_strdupAtoW(lpszString);
1634     file = heap_strdupAtoW(lpszFilename);
1635 
1636     ret = SQLWritePrivateProfileStringW(sect, entry, string, file);
1637 
1638     heap_free(sect);
1639     heap_free(entry);
1640     heap_free(string);
1641     heap_free(file);
1642 
1643     return ret;
1644 }
1645