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. */ 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 */ 86 static void clear_errors(void) 87 { 88 num_errors = 0; 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1317 BOOL WINAPI SQLRemoveDefaultDataSource(void) 1318 { 1319 clear_errors(); 1320 FIXME("\n"); 1321 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1322 return FALSE; 1323 } 1324 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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