[v4 PATCH] odbccp32: Handle ODBC_CONFIG_DRIVER request in SQLConfigDriver/W

Alistair Leslie-Hughes leslie_alistair at hotmail.com
Tue Apr 25 19:46:49 CDT 2017


When SQLInstallerErrorW returns SQL_NO_DATA, the error code isn't
updated when the previous call successed.

v2 - Added more tests to show that arg is a single name=value.
   - Added more error checks
v3 - Fix crash on XP.
v4 - Free Handles on error.
   - Corrected order of test so all tests are run correctly.

Signed-off-by: Alistair Leslie-Hughes <leslie_alistair at hotmail.com>
---
 dlls/odbccp32/odbccp32.c   | 88 ++++++++++++++++++++++++++++++++++++++++++++++
 dlls/odbccp32/tests/misc.c | 65 +++++++++++++++++++++++++++++++---
 2 files changed, 149 insertions(+), 4 deletions(-)

diff --git a/dlls/odbccp32/odbccp32.c b/dlls/odbccp32/odbccp32.c
index f28d464..475b74e 100644
--- a/dlls/odbccp32/odbccp32.c
+++ b/dlls/odbccp32/odbccp32.c
@@ -65,6 +65,7 @@ static const WCHAR odbc_error_invalid_param_string[] = {'I','n','v','a','l','i',
 static const WCHAR odbc_error_invalid_dsn[] = {'I','n','v','a','l','i','d',' ','D','S','N',0};
 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};
 static const WCHAR odbc_error_request_failed[] = {'R','e','q','u','e','s','t',' ','F','a','i','l','e','d',0};
+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};
 
 /* Push an error onto the error stack, taking care of ranges etc. */
 static void push_error(int code, LPCWSTR msg)
@@ -303,6 +304,64 @@ static HMODULE load_config_driver(const WCHAR *driver)
     return hmod;
 }
 
+static BOOL write_config_value(const WCHAR *driver, const WCHAR *args)
+{
+    long ret;
+    HKEY hkey, hkeydriver;
+    WCHAR *name = NULL;
+
+    if (!args)
+        return FALSE;
+
+    if ((ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, odbcini, &hkey)) == ERROR_SUCCESS)
+    {
+        if ((ret = RegOpenKeyW(hkey, driver, &hkeydriver)) == ERROR_SUCCESS)
+        {
+            WCHAR *divider, *value;
+
+            name = heap_alloc( (strlenW(args) + 1) * sizeof(WCHAR));
+            if(!name)
+            {
+                push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
+                goto fail;
+            }
+            lstrcpyW(name, args);
+
+            divider = strchrW(name,'=');
+            if(!divider)
+            {
+                push_error(ODBC_ERROR_INVALID_KEYWORD_VALUE, odbc_error_invalid_keyword);
+                goto fail;
+            }
+
+            value = divider + 1;
+            *divider = '\0';
+
+            TRACE("Write pair: %s = %s\n", debugstr_w(name), debugstr_w(value));
+            if(RegSetValueExW(hkeydriver, name, 0, REG_SZ, (BYTE*)value,
+                               strlenW(value) * sizeof(WCHAR)) != ERROR_SUCCESS)
+                ERR("Failed to write registry installed key\n");
+            heap_free(name);
+
+            RegCloseKey(hkeydriver);
+        }
+
+        RegCloseKey(hkey);
+    }
+
+    if(ret != ERROR_SUCCESS)
+        push_error(ODBC_ERROR_COMPONENT_NOT_FOUND, odbc_error_component_not_found);
+
+    return ret == ERROR_SUCCESS;
+
+fail:
+    RegCloseKey(hkeydriver);
+    RegCloseKey(hkey);
+    heap_free(name);
+
+    return FALSE;
+}
+
 BOOL WINAPI SQLConfigDriverW(HWND hwnd, WORD request, LPCWSTR driver,
                LPCWSTR args, LPWSTR msg, WORD msgmax, WORD *msgout)
 {
@@ -314,6 +373,11 @@ BOOL WINAPI SQLConfigDriverW(HWND hwnd, WORD request, LPCWSTR driver,
     TRACE("(%p %d %s %s %p %d %p)\n", hwnd, request, debugstr_w(driver),
           debugstr_w(args), msg, msgmax, msgout);
 
+    if(request == ODBC_CONFIG_DRIVER)
+    {
+        return write_config_value(driver, args);
+    }
+
     hmod = load_config_driver(driver);
     if(!hmod)
         return FALSE;
@@ -343,6 +407,30 @@ BOOL WINAPI SQLConfigDriver(HWND hwnd, WORD request, LPCSTR driver,
           debugstr_a(args), msg, msgmax, msgout);
 
     driverW = heap_strdupAtoW(driver);
+    if(!driverW)
+    {
+        push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
+        return FALSE;
+    }
+    if(request == ODBC_CONFIG_DRIVER)
+    {
+        BOOL ret = FALSE;
+        WCHAR *argsW = heap_strdupAtoW(args);
+        if(argsW)
+        {
+            ret = write_config_value(driverW, argsW);
+            HeapFree(GetProcessHeap(), 0, argsW);
+        }
+        else
+        {
+            push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
+        }
+
+        HeapFree(GetProcessHeap(), 0, driverW);
+
+        return ret;
+    }
+
     hmod = load_config_driver(driverW);
     HeapFree(GetProcessHeap(), 0, driverW);
     if(!hmod)
diff --git a/dlls/odbccp32/tests/misc.c b/dlls/odbccp32/tests/misc.c
index ed8e6f1..8e119e0 100644
--- a/dlls/odbccp32/tests/misc.c
+++ b/dlls/odbccp32/tests/misc.c
@@ -421,31 +421,63 @@ static void test_SQLInstallDriverEx(void)
     DWORD cnt, error_code = 0;
     HKEY hkey;
     LONG res;
+    char error[1000];
 
     GetSystemDirectoryA(syspath, MAX_PATH);
 
-    SQLInstallDriverEx("WINE ODBC Driver\0Driver=sample.dll\0Setup=sample.dll\0\0", NULL, path, MAX_PATH, &size, ODBC_INSTALL_COMPLETE, NULL);
+    ret = SQLConfigDriver(NULL, ODBC_CONFIG_DRIVER, "WINE ODBC Driver", "CPTimeout=59", error, sizeof(error), NULL);
+    ok(!ret, "SQLConfigDriver returned %d\n", ret);
+    sql_ret = SQLInstallerErrorW(1, &error_code, NULL, 0, NULL);
+    ok(sql_ret && error_code == ODBC_ERROR_COMPONENT_NOT_FOUND, "SQLConfigDriver returned %d, %u\n", sql_ret, error_code);
+
+    ret = SQLInstallDriverEx("WINE ODBC Driver\0Driver=sample.dll\0Setup=sample.dll\0\0", NULL,
+                             path, MAX_PATH, &size, ODBC_INSTALL_COMPLETE, NULL);
+    ok(ret, "SQLInstallDriverEx failed\n");
     sql_ret = SQLInstallerErrorW(1, &error_code, NULL, 0, NULL);
     if (sql_ret && error_code == ODBC_ERROR_WRITING_SYSINFO_FAILED)
     {
          win_skip("not enough privileges\n");
          return;
     }
-    ok(sql_ret && error_code == SQL_SUCCESS, "SQLInstallDriverEx failed %d, %u\n", sql_ret, error_code);
+    ok(sql_ret == SQL_NO_DATA || (sql_ret && error_code == SQL_SUCCESS), "SQLInstallDriverEx failed %d, %u\n", sql_ret, error_code);
     ok(!strcmp(path, syspath), "invalid path %s\n", path);
 
+if (0)  /* Crashes on XP. */
+{
+    sql_ret = 0;
+    ret = SQLConfigDriver(NULL, ODBC_CONFIG_DRIVER, "WINE ODBC Driver", NULL, error, sizeof(error), NULL);
+    ok(!ret, "SQLConfigDriver failed '%s'\n",error);
+}
+
+    ret = SQLConfigDriver(NULL, ODBC_CONFIG_DRIVER, "WINE ODBC Driver", "CPTimeout=59\0NoWrite=60\0", error, sizeof(error), NULL);
+    ok(ret, "SQLConfigDriver failed\n");
+    sql_ret = SQLInstallerErrorW(1, &error_code, NULL, 0, NULL);
+    ok(sql_ret == SQL_NO_DATA || (sql_ret && error_code == SQL_SUCCESS), "SQLConfigDriver failed %d, %u\n", sql_ret, error_code);
+
     ret = SQLInstallDriverEx("WINE ODBC Driver Path\0Driver=sample.dll\0Setup=sample.dll\0\0", "c:\\temp", path, MAX_PATH, &size, ODBC_INSTALL_COMPLETE, NULL);
+    ok(ret, "SQLInstallDriverEx failed\n");
     sql_ret = SQLInstallerErrorW(1, &error_code, NULL, 0, NULL);
-    ok(sql_ret && error_code == SQL_SUCCESS, "SQLInstallDriverEx failed %d, %u\n", sql_ret, error_code);
+    ok(sql_ret == SQL_NO_DATA || (sql_ret && error_code == SQL_SUCCESS), "SQLInstallDriverEx failed %d, %u\n", sql_ret, error_code);
     ok(!strcmp(path, "c:\\temp"), "invalid path %s\n", path);
 
+    ret = SQLConfigDriver(NULL, ODBC_CONFIG_DRIVER, "WINE ODBC Driver Path", "empty", error, sizeof(error), NULL);
+    ok(!ret, "SQLConfigDriver successful\n");
+    sql_ret = SQLInstallerErrorW(1, &error_code, NULL, 0, NULL);
+    ok(sql_ret && error_code == ODBC_ERROR_INVALID_KEYWORD_VALUE, "SQLConfigDriver failed %d, %u\n", sql_ret, error_code);
+
+    ret = SQLConfigDriver(NULL, ODBC_CONFIG_DRIVER, "WINE ODBC Driver Path", "NoWrite=60;xxxx=555", error, sizeof(error), NULL);
+    ok(ret, "SQLConfigDriver failed\n");
+    sql_ret = SQLInstallerErrorW(1, &error_code, NULL, 0, NULL);
+    ok(sql_ret == SQL_NO_DATA || (sql_ret && error_code == SQL_SUCCESS), "SQLConfigDriver failed %d, %u\n", sql_ret, error_code);
+
     if (ret)
     {
+        DWORD type = 0xdeadbeef, size = MAX_PATH;
+
         res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\ODBC\\ODBCINST.INI\\WINE ODBC Driver", 0, KEY_READ, &hkey);
         ok(res == ERROR_SUCCESS, "RegOpenKeyExW failed\n");
         if (res == ERROR_SUCCESS)
         {
-            DWORD type = 0xdeadbeef, size = MAX_PATH;
             char driverpath[MAX_PATH];
 
             strcpy(driverpath, syspath);
@@ -458,6 +490,31 @@ static void test_SQLInstallDriverEx(void)
             ok(size == strlen(driverpath) + 1, "got %u\n", size);
             ok(!strcmp(path, driverpath), "invalid path %s\n", path);
 
+            res = RegQueryValueExA(hkey, "CPTimeout", NULL, &type, (BYTE *)&path, &size);
+            ok(res == ERROR_SUCCESS, "got %d\n", res);
+            ok(type == REG_SZ, "got %u\n", type);
+            ok(size == strlen("59") + 1, "got %u\n", size);
+            ok(!strcmp(path, "59"), "invalid value %s\n", path);
+
+            res = RegQueryValueExA(hkey, "NoWrite", NULL, &type, (BYTE *)&path, &size);
+            ok(res == ERROR_FILE_NOT_FOUND, "got %d\n", res);
+
+            RegCloseKey(hkey);
+        }
+
+        res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\ODBC\\ODBCINST.INI\\WINE ODBC Driver Path", 0, KEY_READ, &hkey);
+        ok(res == ERROR_SUCCESS, "RegOpenKeyExW failed\n");
+        if (res == ERROR_SUCCESS)
+        {
+            size = sizeof(path);
+            res = RegQueryValueExA(hkey, "NoWrite", NULL, &type, (BYTE *)&path, &size);
+            ok(res == ERROR_SUCCESS, "got %d\n", res);
+            ok(type == REG_SZ, "got %u\n", type);
+            ok(size == strlen("60;xxxx=555") + 1, "got %u\n", size);
+            ok(!strcmp(path, "60;xxxx=555"), "invalid value %s\n", path);
+
+            res = RegQueryValueExA(hkey, "CPTimeout", NULL, &type, (BYTE *)&path, &size);
+            ok(res == ERROR_FILE_NOT_FOUND, "got %d\n", res);
             RegCloseKey(hkey);
         }
     }
-- 
1.9.1




More information about the wine-patches mailing list