From 6991563d81011c415505baeeef55b5162f7d2f84 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Thu, 31 Aug 2006 19:52:03 +0900 Subject: [PATCH] msi: Implement MsiDatabaseExport. --- dlls/msi/database.c | 132 +++++++++++++++++++++++++++++++++++++++++++- dlls/msi/tests/db.c | 2 - 2 files changed, 129 insertions(+), 5 deletions(-) diff --git a/dlls/msi/database.c b/dlls/msi/database.c index 609db238988..b92d3bf27a6 100644 --- a/dlls/msi/database.c +++ b/dlls/msi/database.c @@ -287,18 +287,144 @@ end: return r; } +static UINT msi_export_record( HANDLE handle, MSIRECORD *row, UINT start ) +{ + UINT i, count, len, r = ERROR_SUCCESS; + const char *sep; + char *buffer; + DWORD sz; + + len = 0x100; + buffer = msi_alloc( len ); + if ( !buffer ) + return ERROR_OUTOFMEMORY; + + count = MSI_RecordGetFieldCount( row ); + for ( i=start; i<=count; i++ ) + { + sz = len; + r = MSI_RecordGetStringA( row, i, buffer, &sz ); + if (r == ERROR_MORE_DATA) + { + char *p = msi_realloc( buffer, sz + 1 ); + if (!p) + break; + len = sz + 1; + buffer = p; + } + sz = len; + r = MSI_RecordGetStringA( row, i, buffer, &sz ); + if (r != ERROR_SUCCESS) + break; + + if (!WriteFile( handle, buffer, sz, &sz, NULL )) + { + r = ERROR_FUNCTION_FAILED; + break; + } + + sep = (i < count) ? "\t" : "\r\n"; + if (!WriteFile( handle, sep, strlen(sep), &sz, NULL )) + { + r = ERROR_FUNCTION_FAILED; + break; + } + } + msi_free( buffer ); + return r; +} + +static UINT msi_export_row( MSIRECORD *row, void *arg ) +{ + return msi_export_record( arg, row, 1 ); +} + UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table, LPCWSTR folder, LPCWSTR file ) { - FIXME("%p %s %s %s\n", db, debugstr_w(table), + static const WCHAR query[] = { + 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','%','s',0 }; + static const WCHAR szbs[] = { '\\', 0 }; + MSIRECORD *rec = NULL; + MSIQUERY *view = NULL; + LPWSTR filename; + HANDLE handle; + UINT len, r; + + TRACE("%p %s %s %s\n", db, debugstr_w(table), debugstr_w(folder), debugstr_w(file) ); if( folder == NULL || file == NULL ) return ERROR_INVALID_PARAMETER; - - return ERROR_CALL_NOT_IMPLEMENTED; + + len = lstrlenW(folder) + lstrlenW(file) + 2; + filename = msi_alloc(len * sizeof (WCHAR)); + if (!filename) + return ERROR_OUTOFMEMORY; + + lstrcpyW( filename, folder ); + lstrcatW( filename, szbs ); + lstrcatW( filename, file ); + + handle = CreateFileW( filename, GENERIC_READ | GENERIC_WRITE, 0, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + msi_free( filename ); + if (handle == INVALID_HANDLE_VALUE) + return ERROR_FUNCTION_FAILED; + + r = MSI_OpenQuery( db, &view, query, table ); + if (r == ERROR_SUCCESS) + { + /* write out row 1, the column names */ + r = MSI_ViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec); + if (r == ERROR_SUCCESS) + { + msi_export_record( handle, rec, 1 ); + msiobj_release( &rec->hdr ); + } + + /* write out row 2, the column types */ + r = MSI_ViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec); + if (r == ERROR_SUCCESS) + { + msi_export_record( handle, rec, 1 ); + msiobj_release( &rec->hdr ); + } + + /* write out row 3, the table name + keys */ + r = MSI_DatabaseGetPrimaryKeys( db, table, &rec ); + if (r == ERROR_SUCCESS) + { + MSI_RecordSetStringW( rec, 0, table ); + msi_export_record( handle, rec, 0 ); + msiobj_release( &rec->hdr ); + } + + /* write out row 4 onwards, the data */ + r = MSI_IterateRecords( view, 0, msi_export_row, handle ); + msiobj_release( &view->hdr ); + } + + CloseHandle( handle ); + + return r; } +/*********************************************************************** + * MsiExportDatabaseW [MSI.@] + * + * Writes a file containing the table data as tab separated ASCII. + * + * The format is as follows: + * + * row1 : colname1 colname2 .... colnameN + * row2 : coltype1 coltype2 .... coltypeN + * row3 : tablename key1 key2 ... keyM + * + * Followed by the data, starting at row 1 with one row per line + * + * row4 : data data data ... data + */ UINT WINAPI MsiDatabaseExportW( MSIHANDLE handle, LPCWSTR szTable, LPCWSTR szFolder, LPCWSTR szFilename ) { diff --git a/dlls/msi/tests/db.c b/dlls/msi/tests/db.c index b61e643b9d9..52e7fdf579a 100644 --- a/dlls/msi/tests/db.c +++ b/dlls/msi/tests/db.c @@ -856,7 +856,6 @@ static void test_msiexport(void) GetCurrentDirectory(MAX_PATH, path); - todo_wine { r = MsiDatabaseExport(hdb, "phone", path, file); ok(r == ERROR_SUCCESS, "MsiDatabaseExport failed\n"); @@ -880,7 +879,6 @@ static void test_msiexport(void) ok( length == strlen(expected), "length of data wrong\n"); ok( !lstrcmp(buffer, expected), "data doesn't match\n"); - } DeleteFile(msifile); }