diff --git a/dll/win32/msi/alter.c b/dll/win32/msi/alter.c index d1a481ebfc9..5c5893c8248 100644 --- a/dll/win32/msi/alter.c +++ b/dll/win32/msi/alter.c @@ -221,6 +221,7 @@ static const MSIVIEWOPS alter_ops = NULL, NULL, NULL, + NULL, ALTER_execute, ALTER_close, ALTER_get_dimensions, diff --git a/dll/win32/msi/create.c b/dll/win32/msi/create.c index 3c00b70c531..2777954aa7d 100644 --- a/dll/win32/msi/create.c +++ b/dll/win32/msi/create.c @@ -131,6 +131,7 @@ static const MSIVIEWOPS create_ops = NULL, NULL, NULL, + NULL, CREATE_execute, CREATE_close, CREATE_get_dimensions, diff --git a/dll/win32/msi/delete.c b/dll/win32/msi/delete.c index e2e0e34678b..81bd9d7db2f 100644 --- a/dll/win32/msi/delete.c +++ b/dll/win32/msi/delete.c @@ -173,6 +173,7 @@ static const MSIVIEWOPS delete_ops = NULL, NULL, NULL, + NULL, DELETE_execute, DELETE_close, DELETE_get_dimensions, diff --git a/dll/win32/msi/distinct.c b/dll/win32/msi/distinct.c index 5bd5bf8676d..e102adb3de2 100644 --- a/dll/win32/msi/distinct.c +++ b/dll/win32/msi/distinct.c @@ -256,6 +256,7 @@ static const MSIVIEWOPS distinct_ops = NULL, NULL, NULL, + NULL, DISTINCT_execute, DISTINCT_close, DISTINCT_get_dimensions, diff --git a/dll/win32/msi/drop.c b/dll/win32/msi/drop.c index 60a92021060..89fac9dfc7c 100644 --- a/dll/win32/msi/drop.c +++ b/dll/win32/msi/drop.c @@ -101,6 +101,7 @@ static const MSIVIEWOPS drop_ops = NULL, NULL, NULL, + NULL, DROP_execute, DROP_close, DROP_get_dimensions, diff --git a/dll/win32/msi/insert.c b/dll/win32/msi/insert.c index ed913c034c1..f1185eebaeb 100644 --- a/dll/win32/msi/insert.c +++ b/dll/win32/msi/insert.c @@ -327,6 +327,7 @@ static const MSIVIEWOPS insert_ops = NULL, NULL, NULL, + NULL, INSERT_execute, INSERT_close, INSERT_get_dimensions, diff --git a/dll/win32/msi/msipriv.h b/dll/win32/msi/msipriv.h index 8bf0385a440..2177aa6f10e 100644 --- a/dll/win32/msi/msipriv.h +++ b/dll/win32/msi/msipriv.h @@ -256,6 +256,13 @@ typedef struct tagMSIVIEWOPS */ UINT (*set_string)( struct tagMSIVIEW *view, UINT row, UINT col, const WCHAR *val, int len ); + /* + * set_stream - set the stream value at {row, col} + * This function has undefined behaviour if the column does not contain + * streams. + */ + UINT (*set_stream)( struct tagMSIVIEW *view, UINT row, UINT col, IStream *stream ); + /* * set_row - sets values in a row as specified by mask * diff --git a/dll/win32/msi/select.c b/dll/win32/msi/select.c index c6e7b209033..9d3d887f56b 100644 --- a/dll/win32/msi/select.c +++ b/dll/win32/msi/select.c @@ -234,6 +234,7 @@ static UINT msi_select_update(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row) { MSISELECTVIEW *sv = (MSISELECTVIEW*)view; UINT r, i, col, type, val; + IStream *stream; LPCWSTR str; for (i = 0; i < sv->num_cols; i++) @@ -249,8 +250,9 @@ static UINT msi_select_update(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row) if (MSITYPE_IS_BINARY(type)) { - ERR("Cannot modify binary data!\n"); - return ERROR_FUNCTION_FAILED; + if (MSI_RecordGetIStream(rec, i + 1, &stream)) + return ERROR_FUNCTION_FAILED; + r = sv->table->ops->set_stream(sv->table, row, col, stream); } else if (type & MSITYPE_STRING) { @@ -311,6 +313,7 @@ static const MSIVIEWOPS select_ops = SELECT_fetch_stream, NULL, NULL, + NULL, SELECT_set_row, SELECT_insert_row, NULL, diff --git a/dll/win32/msi/storages.c b/dll/win32/msi/storages.c index 76a0e2e03f8..521b6e89e83 100644 --- a/dll/win32/msi/storages.c +++ b/dll/win32/msi/storages.c @@ -153,6 +153,46 @@ done: return hr; } +static UINT STORAGES_set_stream( MSIVIEW *view, UINT row, UINT col, IStream *stream ) +{ + MSISTORAGESVIEW *sv = (MSISTORAGESVIEW *)view; + IStorage *stg, *substg, *prev; + const WCHAR *name; + HRESULT hr; + UINT r; + + TRACE("view %p, row %u, col %u, stream %p.\n", view, row, col, stream); + + if ((r = stream_to_storage(stream, &stg))) + return r; + + name = msi_string_lookup(sv->db->strings, sv->storages[row].str_index, NULL); + + hr = IStorage_CreateStorage(sv->db->storage, name, + STGM_WRITE | STGM_SHARE_EXCLUSIVE, + 0, 0, &substg); + if (FAILED(hr)) + { + IStorage_Release(stg); + return ERROR_FUNCTION_FAILED; + } + + hr = IStorage_CopyTo(stg, 0, NULL, NULL, substg); + if (FAILED(hr)) + { + IStorage_Release(substg); + IStorage_Release(stg); + return ERROR_FUNCTION_FAILED; + } + IStorage_Release(substg); + + prev = sv->storages[row].storage; + sv->storages[row].storage = stg; + if (prev) IStorage_Release(prev); + + return ERROR_SUCCESS; +} + static UINT STORAGES_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask) { MSISTORAGESVIEW *sv = (MSISTORAGESVIEW *)view; @@ -404,6 +444,7 @@ static const MSIVIEWOPS storages_ops = STORAGES_fetch_stream, NULL, STORAGES_set_string, + STORAGES_set_stream, STORAGES_set_row, STORAGES_insert_row, STORAGES_delete_row, diff --git a/dll/win32/msi/streams.c b/dll/win32/msi/streams.c index 150e9288682..6565b3d4c40 100644 --- a/dll/win32/msi/streams.c +++ b/dll/win32/msi/streams.c @@ -110,6 +110,19 @@ static UINT STREAMS_set_string( struct tagMSIVIEW *view, UINT row, UINT col, con return ERROR_FUNCTION_FAILED; } +static UINT STREAMS_set_stream( MSIVIEW *view, UINT row, UINT col, IStream *stream ) +{ + MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; + IStream *prev; + + TRACE("view %p, row %u, col %u, stream %p.\n", view, row, col, stream); + + prev = sv->db->streams[row].stream; + IStream_AddRef(sv->db->streams[row].stream = stream); + if (prev) IStream_Release(prev); + return ERROR_SUCCESS; +} + static UINT STREAMS_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask) { MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; @@ -364,6 +377,7 @@ static const MSIVIEWOPS streams_ops = STREAMS_fetch_stream, NULL, STREAMS_set_string, + STREAMS_set_stream, STREAMS_set_row, STREAMS_insert_row, STREAMS_delete_row, diff --git a/dll/win32/msi/table.c b/dll/win32/msi/table.c index f26ab9f5b45..a2b83e27de2 100644 --- a/dll/win32/msi/table.c +++ b/dll/win32/msi/table.c @@ -1357,6 +1357,22 @@ done: return r; } +static UINT TABLE_set_stream( MSIVIEW *view, UINT row, UINT col, IStream *stream ) +{ + MSITABLEVIEW *tv = (MSITABLEVIEW *)view; + WCHAR *name; + UINT r; + + TRACE("row %u, col %u, stream %p.\n", row, col, stream); + + if ((r = get_stream_name( tv, row - 1, &name ))) + return r; + + r = add_stream( tv->db, name, stream ); + msi_free( name ); + return r; +} + static UINT get_table_value_from_record( MSITABLEVIEW *tv, MSIRECORD *rec, UINT iField, UINT *pvalue ) { MSICOLUMNINFO columninfo; @@ -2126,6 +2142,7 @@ static const MSIVIEWOPS table_ops = TABLE_fetch_stream, TABLE_set_int, TABLE_set_string, + TABLE_set_stream, TABLE_set_row, TABLE_insert_row, TABLE_delete_row, diff --git a/dll/win32/msi/update.c b/dll/win32/msi/update.c index af629d2236c..e61342d11e4 100644 --- a/dll/win32/msi/update.c +++ b/dll/win32/msi/update.c @@ -204,6 +204,7 @@ static const MSIVIEWOPS update_ops = NULL, NULL, NULL, + NULL, UPDATE_execute, UPDATE_close, UPDATE_get_dimensions, diff --git a/dll/win32/msi/where.c b/dll/win32/msi/where.c index eaadac4310c..66de85bec94 100644 --- a/dll/win32/msi/where.c +++ b/dll/win32/msi/where.c @@ -299,6 +299,26 @@ static UINT WHERE_set_string(struct tagMSIVIEW *view, UINT row, UINT col, const return table->view->ops->set_string(table->view, rows[table->table_index], col, val, len); } +static UINT WHERE_set_stream(MSIVIEW *view, UINT row, UINT col, IStream *stream) +{ + MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; + JOINTABLE *table; + UINT *rows; + UINT r; + + TRACE("view %p, row %u, col %u, stream %p.\n", wv, row, col, stream); + + r = find_row(wv, row, &rows); + if (r != ERROR_SUCCESS) + return r; + + table = find_table(wv, col, &col); + if (!table) + return ERROR_FUNCTION_FAILED; + + return table->view->ops->set_stream(table->view, rows[table->table_index], col, stream); +} + static UINT WHERE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask ) { MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; @@ -1098,6 +1118,7 @@ static const MSIVIEWOPS where_ops = WHERE_fetch_stream, WHERE_set_int, WHERE_set_string, + WHERE_set_stream, WHERE_set_row, NULL, WHERE_delete_row,