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