diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 7ea898c1ca2..f386f908389 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -831,6 +831,8 @@ extern UINT msi_record_set_string(MSIRECORD *, UINT, const WCHAR *, int) DECLSPE extern const WCHAR *msi_record_get_string(const MSIRECORD *, UINT, int *) DECLSPEC_HIDDEN; extern void dump_record(MSIRECORD *) DECLSPEC_HIDDEN; extern UINT unmarshal_record(const struct wire_record *in, MSIHANDLE *out) DECLSPEC_HIDDEN; +extern struct wire_record *marshal_record(MSIHANDLE handle) DECLSPEC_HIDDEN; +extern void free_remote_record(struct wire_record *rec) DECLSPEC_HIDDEN; /* stream internals */ extern void enum_stream_names( IStorage *stg ) DECLSPEC_HIDDEN; diff --git a/dlls/msi/msiquery.c b/dlls/msi/msiquery.c index bfc239a53d5..6eddf7a8219 100644 --- a/dlls/msi/msiquery.c +++ b/dlls/msi/msiquery.c @@ -389,8 +389,22 @@ UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record) *record = 0; query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); - if( !query ) - return ERROR_INVALID_HANDLE; + if (!query) + { + struct wire_record *wire_rec = NULL; + MSIHANDLE remote; + + if (!(remote = msi_get_remote(hView))) + return ERROR_INVALID_HANDLE; + + ret = remote_ViewFetch(remote, &wire_rec); + if (!ret) + { + ret = unmarshal_record(wire_rec, record); + free_remote_record(wire_rec); + } + return ret; + } ret = MSI_ViewFetch( query, &rec ); if( ret == ERROR_SUCCESS ) { @@ -1054,3 +1068,14 @@ UINT __cdecl remote_ViewExecute(MSIHANDLE view, struct wire_record *remote_rec) MsiCloseHandle(rec); return r; } + +UINT __cdecl remote_ViewFetch(MSIHANDLE view, struct wire_record **rec) +{ + MSIHANDLE handle; + UINT r = MsiViewFetch(view, &handle); + *rec = NULL; + if (!r) + *rec = marshal_record(handle); + MsiCloseHandle(handle); + return r; +} diff --git a/dlls/msi/record.c b/dlls/msi/record.c index 4c504eac472..91892d7377f 100644 --- a/dlls/msi/record.c +++ b/dlls/msi/record.c @@ -1103,3 +1103,58 @@ UINT unmarshal_record(const struct wire_record *in, MSIHANDLE *out) msiobj_release(&rec->hdr); return ERROR_SUCCESS; } + +struct wire_record *marshal_record(MSIHANDLE handle) +{ + struct wire_record *ret; + unsigned int i, count; + MSIRECORD *rec; + + if (!(rec = msihandle2msiinfo(handle, MSIHANDLETYPE_RECORD))) + return NULL; + + count = MSI_RecordGetFieldCount(rec); + ret = midl_user_allocate(sizeof(*ret) + count * sizeof(ret->fields[0])); + ret->count = count; + + for (i = 0; i <= count; i++) + { + switch (rec->fields[i].type) + { + case MSIFIELD_NULL: + break; + case MSIFIELD_INT: + ret->fields[i].u.iVal = rec->fields[i].u.iVal; + break; + case MSIFIELD_WSTR: + ret->fields[i].u.szwVal = strdupW(rec->fields[i].u.szwVal); + break; + case MSIFIELD_STREAM: + IStream_AddRef(rec->fields[i].u.stream); + ret->fields[i].u.stream = rec->fields[i].u.stream; + break; + default: + ERR("invalid field type %d\n", rec->fields[i].type); + break; + } + ret->fields[i].type = rec->fields[i].type; + } + + msiobj_release(&rec->hdr); + return ret; +} + +void free_remote_record(struct wire_record *rec) +{ + int i; + + for (i = 0; i <= rec->count; i++) + { + if (rec->fields[i].type == MSIFIELD_WSTR) + midl_user_free(rec->fields[i].u.szwVal); + else if (rec->fields[i].type == MSIFIELD_STREAM) + IStream_Release(rec->fields[i].u.stream); + } + + midl_user_free(rec); +} diff --git a/dlls/msi/tests/custom.c b/dlls/msi/tests/custom.c index 8a0a20aff05..479cb930de4 100644 --- a/dlls/msi/tests/custom.c +++ b/dlls/msi/tests/custom.c @@ -243,7 +243,9 @@ static void test_props(MSIHANDLE hinst) static void test_db(MSIHANDLE hinst) { - MSIHANDLE hdb, view, rec; + MSIHANDLE hdb, view, rec, rec2; + char buffer[10]; + DWORD sz; UINT r; hdb = MsiGetActiveDatabase(hinst); @@ -264,6 +266,56 @@ static void test_db(MSIHANDLE hinst) r = MsiViewExecute(view, 0); ok(hinst, !r, "got %u\n", r); + r = MsiViewFetch(view, &rec2); + ok(hinst, !r, "got %u\n", r); + + r = MsiRecordGetFieldCount(rec2); + ok(hinst, r == 3, "got %u\n", r); + + sz = sizeof(buffer); + r = MsiRecordGetStringA(rec2, 1, buffer, &sz); + ok(hinst, !r, "got %u\n", r); + ok(hinst, sz == strlen(buffer), "got size %u\n", sz); + ok(hinst, !strcmp(buffer, "one"), "got '%s'\n", buffer); + + r = MsiRecordGetInteger(rec2, 2); + ok(hinst, r == 1, "got %d\n", r); + + sz = sizeof(buffer); + r = MsiRecordReadStream(rec2, 3, buffer, &sz); + ok(hinst, !r, "got %u\n", r); + ok(hinst, !memcmp(buffer, "unus", 4), "wrong data\n"); + + r = MsiCloseHandle(rec2); + ok(hinst, !r, "got %u\n", r); + + r = MsiViewFetch(view, &rec2); + ok(hinst, !r, "got %u\n", r); + + r = MsiRecordGetFieldCount(rec2); + ok(hinst, r == 3, "got %u\n", r); + + sz = sizeof(buffer); + r = MsiRecordGetStringA(rec2, 1, buffer, &sz); + ok(hinst, !r, "got %u\n", r); + ok(hinst, sz == strlen(buffer), "got size %u\n", sz); + ok(hinst, !strcmp(buffer, "two"), "got '%s'\n", buffer); + + r = MsiRecordGetInteger(rec2, 2); + ok(hinst, r == 2, "got %d\n", r); + + sz = sizeof(buffer); + r = MsiRecordReadStream(rec2, 3, buffer, &sz); + ok(hinst, !r, "got %u\n", r); + ok(hinst, !memcmp(buffer, "duo", 3), "wrong data\n"); + + r = MsiCloseHandle(rec2); + ok(hinst, !r, "got %u\n", r); + + r = MsiViewFetch(view, &rec2); + ok(hinst, r == ERROR_NO_MORE_ITEMS, "got %u\n", r); + ok(hinst, !rec2, "got %u\n", rec2); + r = MsiCloseHandle(view); ok(hinst, !r, "got %u\n", r); @@ -276,6 +328,19 @@ static void test_db(MSIHANDLE hinst) r = MsiViewExecute(view, rec); ok(hinst, !r, "got %u\n", r); + r = MsiViewFetch(view, &rec2); + ok(hinst, !r, "got %u\n", r); + + r = MsiRecordGetInteger(rec2, 2); + ok(hinst, r == 1, "got %d\n", r); + + r = MsiCloseHandle(rec2); + ok(hinst, !r, "got %u\n", r); + + r = MsiViewFetch(view, &rec2); + ok(hinst, r == ERROR_NO_MORE_ITEMS, "got %u\n", r); + ok(hinst, !rec2, "got %u\n", rec2); + r = MsiCloseHandle(rec); ok(hinst, !r, "got %u\n", r); diff --git a/dlls/msi/winemsi.idl b/dlls/msi/winemsi.idl index e698f76e202..b892f34bfea 100644 --- a/dlls/msi/winemsi.idl +++ b/dlls/msi/winemsi.idl @@ -57,6 +57,7 @@ struct wire_record { 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 ); MSICONDITION remote_DatabaseIsTablePersistent( [in] MSIHANDLE db, [in] LPCWSTR table ); HRESULT remote_DatabaseGetPrimaryKeys( [in] MSIHANDLE db, [in] LPCWSTR table, [out] MSIHANDLE *keys );