diff --git a/dlls/msi/format.c b/dlls/msi/format.c index f15c4ceb60c..0533cc004ce 100644 --- a/dlls/msi/format.c +++ b/dlls/msi/format.c @@ -907,43 +907,35 @@ UINT WINAPI MsiFormatRecordW( MSIHANDLE hInstall, MSIHANDLE hRecord, TRACE("%d %d %p %p\n", hInstall, hRecord, szResult, sz); + record = msihandle2msiinfo(hRecord, MSIHANDLETYPE_RECORD); + if (!record) + return ERROR_INVALID_HANDLE; + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); if (!package) { - HRESULT hr; + LPWSTR value = NULL; MSIHANDLE remote; - BSTR value = NULL; awstring wstr; if ((remote = msi_get_remote(hInstall))) { - hr = remote_FormatRecord(remote, hRecord, &value); - if (FAILED(hr)) - goto done; + r = remote_FormatRecord(remote, (struct wire_record *)&record->count, &value); + if (r) + { + midl_user_free(value); + return r; + } wstr.unicode = TRUE; wstr.str.w = szResult; - r = msi_strcpy_to_awstring( value, SysStringLen(value), &wstr, sz ); - -done: - SysFreeString( value ); - - if (FAILED(hr)) - { - if (HRESULT_FACILITY(hr) == FACILITY_WIN32) - return HRESULT_CODE(hr); - - return ERROR_FUNCTION_FAILED; - } + r = msi_strcpy_to_awstring(value, -1, &wstr, sz); + midl_user_free(value); return r; } } - record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); - - if (!record) - return ERROR_INVALID_HANDLE; if (!sz) { msiobj_release( &record->hdr ); diff --git a/dlls/msi/package.c b/dlls/msi/package.c index 6a5d68994f9..4a46df10aba 100644 --- a/dlls/msi/package.c +++ b/dlls/msi/package.c @@ -2555,20 +2555,27 @@ UINT __cdecl remote_SetInstallLevel(MSIHANDLE hinst, int level) return MsiSetInstallLevel(hinst, level); } -HRESULT __cdecl remote_FormatRecord(MSIHANDLE hinst, MSIHANDLE record, - BSTR *value) +UINT __cdecl remote_FormatRecord(MSIHANDLE hinst, struct wire_record *remote_rec, LPWSTR *value) { + WCHAR empty[1]; DWORD size = 0; - UINT r = MsiFormatRecordW(hinst, record, NULL, &size); - if (r == ERROR_SUCCESS) + MSIHANDLE rec; + UINT r; + + if ((r = unmarshal_record(remote_rec, &rec))) + return r; + + r = MsiFormatRecordW(hinst, rec, empty, &size); + if (r == ERROR_MORE_DATA) { - *value = SysAllocStringLen(NULL, size); + *value = midl_user_allocate(++size * sizeof(WCHAR)); if (!*value) - return E_OUTOFMEMORY; - size++; - r = MsiFormatRecordW(hinst, record, *value, &size); + return ERROR_OUTOFMEMORY; + r = MsiFormatRecordW(hinst, rec, *value, &size); } - return HRESULT_FROM_WIN32(r); + + MsiCloseHandle(rec); + return r; } HRESULT __cdecl remote_EvaluateCondition(MSIHANDLE hinst, BSTR condition) diff --git a/dlls/msi/tests/custom.c b/dlls/msi/tests/custom.c index 35b1543407e..76a70adac40 100644 --- a/dlls/msi/tests/custom.c +++ b/dlls/msi/tests/custom.c @@ -750,6 +750,104 @@ static void test_feature_states(MSIHANDLE hinst) ok(hinst, action == INSTALLSTATE_LOCAL, "got action %d\n", action); } +static void test_format_record(MSIHANDLE hinst) +{ + static const WCHAR xyzW[] = {'f','o','o',' ','1','2','3',0}; + static const WCHAR xyW[] = {'f','o','o',' ','1','2',0}; + WCHAR bufferW[10]; + char buffer[10]; + MSIHANDLE rec; + DWORD sz; + UINT r; + + r = MsiFormatRecordA(hinst, 0, NULL, NULL); + ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r); + + rec = MsiCreateRecord(1); + MsiRecordSetStringA(rec, 0, "foo [1]"); + MsiRecordSetInteger(rec, 1, 123); + + r = MsiFormatRecordA(hinst, rec, NULL, NULL); + ok(hinst, !r, "got %u\n", r); + + r = MsiFormatRecordA(hinst, rec, buffer, NULL); + ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r); + + /* Returned size is in bytes, not chars, but only for custom actions. */ + + sz = 0; + r = MsiFormatRecordA(hinst, rec, NULL, &sz); + ok(hinst, !r, "got %u\n", r); + todo_wine_ok(hinst, sz == 14, "got size %u\n", sz); + + sz = 0; + strcpy(buffer,"q"); + r = MsiFormatRecordA(hinst, rec, buffer, &sz); + ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r); + ok(hinst, !strcmp(buffer, "q"), "got \"%s\"\n", buffer); + todo_wine_ok(hinst, sz == 14, "got size %u\n", sz); + + sz = 1; + strcpy(buffer,"x"); + r = MsiFormatRecordA(hinst, rec, buffer, &sz); + ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r); + ok(hinst, !buffer[0], "got \"%s\"\n", buffer); + todo_wine_ok(hinst, sz == 14, "got size %u\n", sz); + + sz = 7; + strcpy(buffer,"x"); + r = MsiFormatRecordA(hinst, rec, buffer, &sz); + ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r); + ok(hinst, !strcmp(buffer, "foo 12"), "got \"%s\"\n", buffer); + todo_wine_ok(hinst, sz == 14, "got size %u\n", sz); + + sz = 8; + strcpy(buffer,"x"); + r = MsiFormatRecordA(hinst, rec, buffer, &sz); + ok(hinst, !r, "got %u\n", r); + ok(hinst, !strcmp(buffer, "foo 123"), "got \"%s\"\n", buffer); + ok(hinst, sz == 7, "got size %u\n", sz); + + sz = 0; + bufferW[0] = 'q'; + r = MsiFormatRecordW(hinst, rec, bufferW, &sz); + ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r); + ok(hinst, bufferW[0] == 'q', "got %s\n", dbgstr_w(bufferW)); + ok(hinst, sz == 7, "got size %u\n", sz); + + sz = 1; + bufferW[0] = 'q'; + r = MsiFormatRecordW(hinst, rec, bufferW, &sz); + ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r); + ok(hinst, !bufferW[0], "got %s\n", dbgstr_w(bufferW)); + ok(hinst, sz == 7, "got size %u\n", sz); + + sz = 7; + bufferW[0] = 'q'; + r = MsiFormatRecordW(hinst, rec, bufferW, &sz); + ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r); + ok(hinst, !lstrcmpW(bufferW, xyW), "got %s\n", dbgstr_w(bufferW)); + ok(hinst, sz == 7, "got size %u\n", sz); + + sz = 8; + bufferW[0] = 'q'; + r = MsiFormatRecordW(hinst, rec, bufferW, &sz); + ok(hinst, !r, "got %u\n", r); + ok(hinst, !lstrcmpW(bufferW, xyzW), "got %s\n", dbgstr_w(bufferW)); + ok(hinst, sz == 7, "got size %u\n", sz); + + /* check that properties work */ + MsiSetPropertyA(hinst, "fmtprop", "foobar"); + MsiRecordSetStringA(rec, 0, "[fmtprop]"); + sz = sizeof(buffer); + r = MsiFormatRecordA(hinst, rec, buffer, &sz); + ok(hinst, !r, "got %u\n", r); + ok(hinst, !strcmp(buffer, "foobar"), "got \"%s\"\n", buffer); + ok(hinst, sz == 6, "got size %u\n", sz); + + MsiCloseHandle(rec); +} + /* 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) @@ -779,6 +877,7 @@ UINT WINAPI main_test(MSIHANDLE hinst) test_targetpath(hinst); test_misc(hinst); test_feature_states(hinst); + test_format_record(hinst); return ERROR_SUCCESS; } diff --git a/dlls/msi/winemsi.idl b/dlls/msi/winemsi.idl index a8e9348ecdf..7d7054a7076 100644 --- a/dlls/msi/winemsi.idl +++ b/dlls/msi/winemsi.idl @@ -87,7 +87,7 @@ interface IWineMsiRemote UINT remote_SetComponentState( [in] MSIHANDLE hinst, [in, string] LPCWSTR component, [in] INSTALLSTATE state ); LANGID remote_GetLanguage( [in] MSIHANDLE hinst ); UINT remote_SetInstallLevel( [in] MSIHANDLE hinst, [in] int level ); - HRESULT remote_FormatRecord( [in] MSIHANDLE hinst, [in] MSIHANDLE record, [out] BSTR *value ); + UINT remote_FormatRecord( [in] MSIHANDLE hinst, [in] struct wire_record *record, [out, string] LPWSTR *value); HRESULT remote_EvaluateCondition( [in] MSIHANDLE hinst, [in] BSTR condition ); HRESULT remote_GetFeatureCost( [in] MSIHANDLE hinst, [in] BSTR feature, [in] INT cost_tree, [in] INSTALLSTATE state, [out] INT *cost ); HRESULT remote_EnumComponentCosts( [in] MSIHANDLE hinst, [in] BSTR component, [in] DWORD index, [in] INSTALLSTATE state,