From f4d30930a653aea1072ef3e08638fd373fd14da3 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Fri, 5 Feb 2021 16:19:45 +1100 Subject: [PATCH] odbccp32: Implement SQLWriteDSNToIni/W. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50150 Signed-off-by: Alistair Leslie-Hughes Signed-off-by: Alexandre Julliard (cherry picked from commit ea3096bdab8fb865f63496613d1db09a105330dc) Signed-off-by: Michael Stefaniuc --- dlls/odbccp32/odbccp32.c | 72 +++++++++++++++++++++++-- dlls/odbccp32/tests/misc.c | 108 +++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+), 5 deletions(-) diff --git a/dlls/odbccp32/odbccp32.c b/dlls/odbccp32/odbccp32.c index 420f206b700..1c46584cd29 100644 --- a/dlls/odbccp32/odbccp32.c +++ b/dlls/odbccp32/odbccp32.c @@ -1691,16 +1691,78 @@ BOOL WINAPI SQLValidDSN(LPCSTR lpszDSN) BOOL WINAPI SQLWriteDSNToIniW(LPCWSTR lpszDSN, LPCWSTR lpszDriver) { + DWORD ret; + HKEY hkey, hkeydriver; + WCHAR filename[MAX_PATH]; + + TRACE("%s %s\n", debugstr_w(lpszDSN), debugstr_w(lpszDriver)); + clear_errors(); - FIXME("%s %s\n", debugstr_w(lpszDSN), debugstr_w(lpszDriver)); - return TRUE; + + if (!SQLValidDSNW(lpszDSN)) + { + push_error(ODBC_ERROR_INVALID_DSN, odbc_error_invalid_dsn); + return FALSE; + } + + /* It doesn't matter if we cannot find the driver, windows just writes a blank value. */ + filename[0] = 0; + if (RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey) == ERROR_SUCCESS) + { + HKEY hkeydriver; + + if (RegOpenKeyW(hkey, lpszDriver, &hkeydriver) == ERROR_SUCCESS) + { + DWORD size = MAX_PATH * sizeof(WCHAR); + RegGetValueW(hkeydriver, NULL, L"driver", RRF_RT_REG_SZ, NULL, filename, &size); + RegCloseKey(hkeydriver); + } + RegCloseKey(hkey); + } + + if ((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\ODBC\\ODBC.INI", &hkey)) == ERROR_SUCCESS) + { + HKEY sources; + + if ((ret = RegCreateKeyW(hkey, L"ODBC Data Sources", &sources)) == ERROR_SUCCESS) + { + RegSetValueExW(sources, lpszDSN, 0, REG_SZ, (BYTE*)lpszDriver, (lstrlenW(lpszDriver)+1)*sizeof(WCHAR)); + RegCloseKey(sources); + + RegDeleteTreeW(hkey, lpszDSN); + if ((ret = RegCreateKeyW(hkey, lpszDSN, &hkeydriver)) == ERROR_SUCCESS) + { + RegSetValueExW(sources, L"driver", 0, REG_SZ, (BYTE*)filename, (lstrlenW(filename)+1)*sizeof(WCHAR)); + RegCloseKey(hkeydriver); + } + } + RegCloseKey(hkey); + } + + if (ret != ERROR_SUCCESS) + push_error(ODBC_ERROR_REQUEST_FAILED, odbc_error_request_failed); + + return ret == ERROR_SUCCESS; } BOOL WINAPI SQLWriteDSNToIni(LPCSTR lpszDSN, LPCSTR lpszDriver) { - clear_errors(); - FIXME("%s %s\n", debugstr_a(lpszDSN), debugstr_a(lpszDriver)); - return TRUE; + BOOL ret = FALSE; + WCHAR *dsn, *driver; + + TRACE("%s %s\n", debugstr_a(lpszDSN), debugstr_a(lpszDriver)); + + dsn = SQLInstall_strdup(lpszDSN); + driver = SQLInstall_strdup(lpszDriver); + if (dsn && driver) + ret = SQLWriteDSNToIniW(dsn, driver); + else + push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem); + + heap_free(dsn); + heap_free(driver); + + return ret; } BOOL WINAPI SQLWriteFileDSNW(LPCWSTR lpszFileName, LPCWSTR lpszAppName, diff --git a/dlls/odbccp32/tests/misc.c b/dlls/odbccp32/tests/misc.c index 0120504227d..f52dcee7acd 100644 --- a/dlls/odbccp32/tests/misc.c +++ b/dlls/odbccp32/tests/misc.c @@ -771,6 +771,113 @@ static void test_SQLConfigDataSource(void) check_error(ODBC_ERROR_COMPONENT_NOT_FOUND); } +static void test_SQLWriteDSNToIni(void) +{ + BOOL ret; + char buffer[MAX_PATH]; + char path[MAX_PATH]; + DWORD type, size; + + SQLSetConfigMode(ODBC_SYSTEM_DSN); + + ret = SQLWriteDSNToIni("wine_dbs", "SQL Server"); + if (!ret) + { + win_skip("Doesn't have permission to write a System DSN\n"); + return; + } + + if(ret) + { + HKEY hkey; + LONG res; + + res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\ODBC\\ODBC.INI\\ODBC Data Sources", 0, + KEY_READ, &hkey); + ok(res == ERROR_SUCCESS, "RegOpenKeyExW failed\n"); + if (res == ERROR_SUCCESS) + { + type = 0xdeadbeef; + size = MAX_PATH; + + memset(buffer, 0, sizeof(buffer)); + res = RegQueryValueExA(hkey, "wine_dbs", NULL, &type, (BYTE *)buffer, &size); + ok(res == ERROR_SUCCESS, "RegGetValueA failed\n"); + ok(type == REG_SZ, "got %u\n", type); + ok(!strcmp(buffer, "SQL Server"), "incorrect string '%s'\n", buffer); + + RegCloseKey(hkey); + } + + res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\ODBC\\ODBC.INI\\wine_dbs", 0, + KEY_READ, &hkey); + ok(res == ERROR_SUCCESS, "RegOpenKeyExW failed\n"); + if (res == ERROR_SUCCESS) + { + type = 0xdeadbeef; + size = MAX_PATH; + + memset(path, 0, sizeof(path)); + res = RegQueryValueExA(hkey, "driver", NULL, &type, (BYTE *)path, &size); + ok(res == ERROR_SUCCESS, "RegGetValueA failed\n"); + ok(type == REG_SZ, "got %u\n", type); + /* WINE doesn't have a 'SQL Server' driver available */ + todo_wine ok(strlen(path) != 0, "Invalid value\n"); + + RegCloseKey(hkey); + } + + ret = SQLRemoveDSNFromIni("wine_dbs"); + ok(ret, "got %d\n", ret); + } + + /* Show that values are writen, even though an invalid driver was specified. */ + ret = SQLWriteDSNToIni("wine_mis", "Missing Access Driver (*.mis)"); + ok(ret, "got %d\n", ret); + if(ret) + { + HKEY hkey; + LONG res; + + res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\ODBC\\ODBC.INI\\ODBC Data Sources", 0, + KEY_READ, &hkey); + ok(res == ERROR_SUCCESS, "RegOpenKeyExW failed\n"); + if (res == ERROR_SUCCESS) + { + type = 0xdeadbeef; + size = MAX_PATH; + + memset(buffer, 0, sizeof(buffer)); + res = RegQueryValueExA(hkey, "wine_mis", NULL, &type, (BYTE *)buffer, &size); + ok(res == ERROR_SUCCESS, "RegGetValueA failed\n"); + ok(type == REG_SZ, "got %u\n", type); + ok(!strcmp(buffer, "Missing Access Driver (*.mis)"), "incorrect string '%s'\n", buffer); + + RegCloseKey(hkey); + } + + res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\ODBC\\ODBC.INI\\wine_mis", 0, + KEY_READ, &hkey); + ok(res == ERROR_SUCCESS, "RegOpenKeyExW failed\n"); + if (res == ERROR_SUCCESS) + { + type = 0xdeadbeef; + size = MAX_PATH; + + memset(path, 0, sizeof(path)); + res = RegQueryValueExA(hkey, "driver", NULL, &type, (BYTE *)path, &size); + ok(res == ERROR_SUCCESS, "RegGetValueA failed\n"); + ok(type == REG_SZ, "got %u\n", type); + ok(strlen(path) == 0, "Invalid value\n"); + + RegCloseKey(hkey); + } + + ret = SQLRemoveDSNFromIni("wine_mis"); + ok(ret, "got %d\n", ret); + } +} + START_TEST(misc) { test_SQLConfigMode(); @@ -785,4 +892,5 @@ START_TEST(misc) test_SQLValidDSN(); test_SQLValidDSNW(); test_SQLConfigDataSource(); + test_SQLWriteDSNToIni(); }