Mike McCormack : msi: Implement MsiDatabaseExport.

Alexandre Julliard julliard at wine.codeweavers.com
Thu Sep 7 05:07:11 CDT 2006


Module: wine
Branch: master
Commit: 6991563d81011c415505baeeef55b5162f7d2f84
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=6991563d81011c415505baeeef55b5162f7d2f84

Author: Mike McCormack <mike at codeweavers.com>
Date:   Thu Aug 31 19:52:03 2006 +0900

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 609db23..b92d3bf 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 <tab> colname2 <tab> .... colnameN <cr> <lf>
+ * row2 : coltype1 <tab> coltype2 <tab> .... coltypeN <cr> <lf>
+ * row3 : tablename <tab> key1 <tab> key2 <tab> ... keyM <cr> <lf>
+ *
+ * Followed by the data, starting at row 1 with one row per line
+ *
+ * row4 : data <tab> data <tab> data <tab> ... data <cr> <lf>
+ */
 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 b61e643..52e7fdf 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);
 }
 




More information about the wine-cvs mailing list