[v3 PATCH resend] odbccp32: Implement SQLWriteDSNToIni/W

Alistair Leslie-Hughes leslie_alistair at hotmail.com
Mon Jan 18 01:04:27 CST 2021


Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=50150

Signed-off-by: Alistair Leslie-Hughes <leslie_alistair at hotmail.com>
---
 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




More information about the wine-devel mailing list