From 942964fdfbd0cb2af1ea6a1c681fc73d399bcce3 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Tue, 26 Mar 2019 18:56:17 -0500 Subject: [PATCH] msi: Handle the remote case in MsiViewGetError(). Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46830 Signed-off-by: Zebediah Figura Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/msi/msiquery.c | 80 +++++++++++++++++++++++++++--- dlls/msi/tests/custom.c | 104 +++++++++++++++++++++++++++++++++++++++ dlls/msi/tests/install.c | 15 ++++++ dlls/msi/winemsi.idl | 2 + 4 files changed, 195 insertions(+), 6 deletions(-) diff --git a/dlls/msi/msiquery.c b/dlls/msi/msiquery.c index 3c22a2159f5..2569d214c9c 100644 --- a/dlls/msi/msiquery.c +++ b/dlls/msi/msiquery.c @@ -778,9 +778,35 @@ MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR buffer, LPDWORD buf if (!buflen) return MSIDBERROR_INVALIDARG; - query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW ); - if( !query ) - return MSIDBERROR_INVALIDARG; + if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW))) + { + WCHAR *remote_column = NULL; + MSIHANDLE remote; + + if (!(remote = msi_get_remote(handle))) + return MSIDBERROR_INVALIDARG; + + if (!*buflen) + return MSIDBERROR_FUNCTIONERROR; + + __TRY + { + r = remote_ViewGetError(remote, &remote_column); + } + __EXCEPT(rpc_filter) + { + r = GetExceptionCode(); + } + __ENDTRY; + + if (msi_strncpyW(remote_column ? remote_column : szEmpty, -1, buffer, buflen) == ERROR_MORE_DATA) + r = MSIDBERROR_MOREDATA; + + if (remote_column) + midl_user_free(remote_column); + + return r; + } if ((r = query->view->error)) column = query->view->error_column; else column = szEmpty; @@ -803,9 +829,35 @@ MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR buffer, LPDWORD bufl if (!buflen) return MSIDBERROR_INVALIDARG; - query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW ); - if (!query) - return MSIDBERROR_INVALIDARG; + if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW))) + { + WCHAR *remote_column = NULL; + MSIHANDLE remote; + + if (!(remote = msi_get_remote(handle))) + return MSIDBERROR_INVALIDARG; + + if (!*buflen) + return MSIDBERROR_FUNCTIONERROR; + + __TRY + { + r = remote_ViewGetError(remote, &remote_column); + } + __EXCEPT(rpc_filter) + { + r = GetExceptionCode(); + } + __ENDTRY; + + if (msi_strncpyWtoA(remote_column ? remote_column : szEmpty, -1, buffer, buflen, FALSE) == ERROR_MORE_DATA) + r = MSIDBERROR_MOREDATA; + + if (remote_column) + midl_user_free(remote_column); + + return r; + } if ((r = query->view->error)) column = query->view->error_column; else column = szEmpty; @@ -1199,6 +1251,22 @@ UINT __cdecl s_remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct return r; } +MSIDBERROR __cdecl s_remote_ViewGetError(MSIHANDLE view, LPWSTR *column) +{ + WCHAR empty[1]; + DWORD size = 1; + UINT r; + + r = MsiViewGetErrorW(view, empty, &size); + if (r == MSIDBERROR_MOREDATA) + { + if (!(*column = midl_user_allocate(++size * sizeof(WCHAR)))) + return MSIDBERROR_FUNCTIONERROR; + r = MsiViewGetErrorW(view, *column, &size); + } + return r; +} + UINT __cdecl s_remote_ViewModify(MSIHANDLE view, MSIMODIFY mode, struct wire_record *remote_rec, struct wire_record **remote_refreshed) { diff --git a/dlls/msi/tests/custom.c b/dlls/msi/tests/custom.c index 43b8369b17f..3a189efff68 100644 --- a/dlls/msi/tests/custom.c +++ b/dlls/msi/tests/custom.c @@ -1159,6 +1159,109 @@ static void test_invalid_functions(MSIHANDLE hinst) MsiCloseHandle(db); } +static void test_view_get_error(MSIHANDLE hinst) +{ + MSIHANDLE db, view, rec; + char buffer[5]; + MSIDBERROR err; + DWORD sz; + UINT r; + + db = MsiGetActiveDatabase(hinst); + ok(hinst, db, "MsiGetActiveDatabase failed\n"); + + r = MsiDatabaseOpenViewA(db, "SELECT * FROM `test2`", &view); + ok(hinst, !r, "got %u\n", r); + + r = MsiViewExecute(view, 0); + ok(hinst, !r, "got %u\n", r); + + sz = 0; + err = MsiViewGetErrorA(0, NULL, &sz); + todo_wine ok(hinst, err == MSIDBERROR_FUNCTIONERROR, "got %d\n", err); + ok(hinst, sz == 0, "got size %u\n", sz); + + err = MsiViewGetErrorA(view, NULL, NULL); + ok(hinst, err == MSIDBERROR_INVALIDARG, "got %d\n", err); + + sz = 0; + err = MsiViewGetErrorA(view, NULL, &sz); + ok(hinst, err == MSIDBERROR_FUNCTIONERROR, "got %d\n", err); + ok(hinst, sz == 0, "got size %u\n", sz); + + sz = 0; + strcpy(buffer, "x"); + err = MsiViewGetErrorA(view, buffer, &sz); + ok(hinst, err == MSIDBERROR_FUNCTIONERROR, "got %d\n", err); + ok(hinst, !strcmp(buffer, "x"), "got \"%s\"\n", buffer); + ok(hinst, sz == 0, "got size %u\n", sz); + + sz = 1; + strcpy(buffer, "x"); + err = MsiViewGetErrorA(view, buffer, &sz); + ok(hinst, err == MSIDBERROR_NOERROR, "got %d\n", err); + ok(hinst, !buffer[0], "got \"%s\"\n", buffer); + ok(hinst, sz == 0, "got size %u\n", sz); + + rec = MsiCreateRecord(2); + MsiRecordSetInteger(rec, 1, 1); + MsiRecordSetInteger(rec, 2, 2); + r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec); + ok(hinst, r == ERROR_INVALID_DATA, "got %u\n", r); + + sz = 2; + strcpy(buffer, "x"); + err = MsiViewGetErrorA(view, buffer, &sz); + ok(hinst, err == MSIDBERROR_DUPLICATEKEY, "got %d\n", err); + ok(hinst, !strcmp(buffer, "A"), "got \"%s\"\n", buffer); + ok(hinst, sz == 1, "got size %u\n", sz); + + sz = 2; + strcpy(buffer, "x"); + err = MsiViewGetErrorA(view, buffer, &sz); + todo_wine ok(hinst, err == MSIDBERROR_NOERROR, "got %d\n", err); + todo_wine ok(hinst, !buffer[0], "got \"%s\"\n", buffer); + todo_wine ok(hinst, sz == 0, "got size %u\n", sz); + + r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec); + ok(hinst, r == ERROR_INVALID_DATA, "got %u\n", r); + + sz = 1; + strcpy(buffer, "x"); + err = MsiViewGetErrorA(view, buffer, &sz); + ok(hinst, err == MSIDBERROR_MOREDATA, "got %d\n", err); + ok(hinst, !buffer[0], "got \"%s\"\n", buffer); + ok(hinst, sz == 1, "got size %u\n", sz); + + sz = 1; + strcpy(buffer, "x"); + err = MsiViewGetErrorA(view, buffer, &sz); + todo_wine ok(hinst, err == MSIDBERROR_NOERROR, "got %d\n", err); + ok(hinst, !buffer[0], "got \"%s\"\n", buffer); + todo_wine ok(hinst, sz == 0, "got size %u\n", sz); + + r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec); + ok(hinst, r == ERROR_INVALID_DATA, "got %u\n", r); + + sz = 0; + strcpy(buffer, "x"); + err = MsiViewGetErrorA(view, buffer, &sz); + ok(hinst, err == MSIDBERROR_FUNCTIONERROR, "got %d\n", err); + ok(hinst, !strcmp(buffer, "x"), "got \"%s\"\n", buffer); + ok(hinst, sz == 0, "got size %u\n", sz); + + sz = 0; + strcpy(buffer, "x"); + err = MsiViewGetErrorA(view, buffer, &sz); + ok(hinst, err == MSIDBERROR_FUNCTIONERROR, "got %d\n", err); + ok(hinst, !strcmp(buffer, "x"), "got \"%s\"\n", buffer); + ok(hinst, sz == 0, "got size %u\n", sz); + + MsiCloseHandle(rec); + MsiCloseHandle(view); + MsiCloseHandle(db); +} + /* Main test. Anything that doesn't depend on a specific install configuration * or have undesired side effects should go here. */ UINT WINAPI main_test(MSIHANDLE hinst) @@ -1186,6 +1289,7 @@ UINT WINAPI main_test(MSIHANDLE hinst) test_format_record(hinst); test_costs(hinst); test_invalid_functions(hinst); + test_view_get_error(hinst); return ERROR_SUCCESS; } diff --git a/dlls/msi/tests/install.c b/dlls/msi/tests/install.c index 27dc83f87e2..e348f327011 100644 --- a/dlls/msi/tests/install.c +++ b/dlls/msi/tests/install.c @@ -700,6 +700,19 @@ static const CHAR ca1_test_seq_dat[] = "Action\tCondition\tSequence\n" "nested1\t\t1\n" "nested51\t\t2\n"; +static const CHAR ca1_test2_dat[] = + "A\tB\n" + "i2\ti2\n" + "test2\tA\n" + "1\t2\n"; + +static const CHAR ca1__validation_dat[] = + "Table\tColumn\tNullable\tMinValue\tMaxValue\tKeyTable\tKeyColumn\tCategory\tSet\tDescription\n" + "s32\ts32\ts4\tI4\tI4\tS255\tI2\tS32\tS255\tS255\n" + "_Validation\tTable\tColumn\n" + "test2\tA\tN\t\t\t\t\t\t\t\n" + "test2\tB\tN\t\t\t\t\t\t\t\n"; + static const CHAR ca51_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" "s72\tS38\ts72\ti2\tS255\tS72\n" "Component\tComponent\n" @@ -1714,6 +1727,8 @@ static const msi_table ca1_tables[] = ADD_TABLE(ca1_install_exec_seq), ADD_TABLE(ca1_custom_action), ADD_TABLE(ca1_test_seq), + ADD_TABLE(ca1_test2), + ADD_TABLE(ca1__validation), }; static const msi_table ca51_tables[] = diff --git a/dlls/msi/winemsi.idl b/dlls/msi/winemsi.idl index 16586036949..7888b0ceb40 100644 --- a/dlls/msi/winemsi.idl +++ b/dlls/msi/winemsi.idl @@ -32,6 +32,7 @@ typedef int INSTALLSTATE; typedef int MSICOLINFO; typedef int MSIMODIFY; typedef int MSICOSTTREE; +typedef int MSIDBERROR; #define MSIFIELD_NULL 0 #define MSIFIELD_INT 1 @@ -68,6 +69,7 @@ interface IWineMsiRemote UINT remote_ViewExecute( [in] MSIHANDLE view, [in, unique] struct wire_record *record ); UINT remote_ViewFetch( [in] MSIHANDLE view, [out] struct wire_record **record ); UINT remote_ViewGetColumnInfo( [in] MSIHANDLE view, [in] MSICOLINFO info, [out] struct wire_record **record ); + MSIDBERROR remote_ViewGetError( [in] MSIHANDLE view, [out, string] LPWSTR *column ); UINT remote_ViewModify( [in] MSIHANDLE view, [in] MSIMODIFY mode, [in] struct wire_record *record, [out] struct wire_record **refreshed );