From 97de1cf5ea27e1da413cd628e8eb3ec1d4f9fd38 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 26 Nov 2020 21:57:29 +1100 Subject: [PATCH] odbccp32: Implement SQLWriteDSNToIni/W Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=50150 Signed-off-by: Alistair Leslie-Hughes --- dlls/odbccp32/odbccp32.c | 96 +++++++++++++++++++++++++++++++-- dlls/odbccp32/tests/misc.c | 108 +++++++++++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+), 5 deletions(-) diff --git a/dlls/odbccp32/odbccp32.c b/dlls/odbccp32/odbccp32.c index 420f206b700..53ca70c0b9f 100644 --- a/dlls/odbccp32/odbccp32.c +++ b/dlls/odbccp32/odbccp32.c @@ -1691,16 +1691,102 @@ BOOL WINAPI SQLValidDSN(LPCSTR lpszDSN) BOOL WINAPI SQLWriteDSNToIniW(LPCWSTR lpszDSN, LPCWSTR lpszDriver) { + BOOL ret = FALSE; + HKEY hkey, hkeydriver; + WCHAR *filename = NULL; + DWORD size = 0, type; + + 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. */ + if ((ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey)) == ERROR_SUCCESS) + { + HKEY hkeydriver; + + if ((ret = RegOpenKeyW(hkey, lpszDriver, &hkeydriver)) == ERROR_SUCCESS) + { + ret = RegGetValueW(hkeydriver, NULL, L"driver", RRF_RT_REG_SZ, &type, NULL, &size); + /* Windows ignores the fact the driver key is missing */ + if(ret == ERROR_SUCCESS && type == REG_SZ && size) + { + filename = HeapAlloc(GetProcessHeap(), 0, size); + if(!filename) + { + RegCloseKey(hkeydriver); + RegCloseKey(hkey); + push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem); + + return FALSE; + } + ret = RegGetValueW(hkeydriver, NULL, L"driver", RRF_RT_REG_SZ, &type, filename, &size); + } + + RegCloseKey(hkeydriver); + } + + RegCloseKey(hkey); + } + + if (RegCreateKeyW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\ODBC\\ODBC.INI", &hkey) == ERROR_SUCCESS) + { + HKEY sources; + + if (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 (RegCreateKeyW(hkey, lpszDSN, &hkeydriver) == ERROR_SUCCESS) + { + if (filename) + RegSetValueExW(sources, L"driver", 0, REG_SZ, (BYTE*)filename, (lstrlenW(filename)+1)*sizeof(WCHAR)); + else + RegSetValueExW(sources, L"driver", 0, REG_SZ, (BYTE*)L"", sizeof(L"")); + + RegCloseKey(hkeydriver); + ret = TRUE; + } + + RegCloseKey(hkey); + } + + if (!ret) + push_error(ODBC_ERROR_REQUEST_FAILED, odbc_error_request_failed); + + heap_free(filename); + + return ret; } 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(); } -- 2.29.2