mirror of
https://github.com/reactos/reactos.git
synced 2025-05-25 20:18:22 +00:00
Autosyncing with Wine HEAD
svn path=/trunk/; revision=24002
This commit is contained in:
parent
b5957ce896
commit
4246de3191
17 changed files with 6177 additions and 5530 deletions
|
@ -3488,32 +3488,25 @@ end:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
|
||||
static UINT msi_get_local_package_name( LPWSTR path )
|
||||
{
|
||||
static const WCHAR installerPathFmt[] = {
|
||||
'%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
|
||||
static const WCHAR fmt[] = {
|
||||
'%','s','\\',
|
||||
'I','n','s','t','a','l','l','e','r','\\',
|
||||
'%','x','.','m','s','i',0};
|
||||
static const WCHAR szOriginalDatabase[] =
|
||||
{'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
|
||||
WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
|
||||
INT num, start;
|
||||
LPWSTR msiFilePath;
|
||||
BOOL r;
|
||||
static const WCHAR szInstaller[] = {
|
||||
'\\','I','n','s','t','a','l','l','e','r','\\',0};
|
||||
static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
|
||||
DWORD time, len, i;
|
||||
HANDLE handle;
|
||||
|
||||
/* copy the package locally */
|
||||
num = GetTickCount() & 0xffff;
|
||||
if (!num)
|
||||
num = 1;
|
||||
start = num;
|
||||
GetWindowsDirectoryW( windir, MAX_PATH );
|
||||
snprintfW( packagefile, MAX_PATH, fmt, windir, num );
|
||||
do
|
||||
time = GetTickCount();
|
||||
GetWindowsDirectoryW( path, MAX_PATH );
|
||||
lstrcatW( path, szInstaller );
|
||||
CreateDirectoryW( path, NULL );
|
||||
|
||||
len = lstrlenW(path);
|
||||
for (i=0; i<0x10000; i++)
|
||||
{
|
||||
HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
|
||||
snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
|
||||
handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
|
@ -3521,13 +3514,23 @@ static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
|
|||
}
|
||||
if (GetLastError() != ERROR_FILE_EXISTS &&
|
||||
GetLastError() != ERROR_SHARING_VIOLATION)
|
||||
break;
|
||||
if (!(++num & 0xffff)) num = 1;
|
||||
sprintfW(packagefile,fmt,num);
|
||||
} while (num != start);
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
snprintfW( path, MAX_PATH, installerPathFmt, windir );
|
||||
create_full_pathW(path);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
|
||||
{
|
||||
static const WCHAR szOriginalDatabase[] =
|
||||
{'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
|
||||
WCHAR packagefile[MAX_PATH];
|
||||
LPWSTR msiFilePath;
|
||||
UINT r;
|
||||
|
||||
r = msi_get_local_package_name( packagefile );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
TRACE("Copying to local package %s\n",debugstr_w(packagefile));
|
||||
|
||||
|
|
|
@ -221,17 +221,35 @@ static const MSIVIEWOPS create_ops =
|
|||
CREATE_delete
|
||||
};
|
||||
|
||||
static UINT check_columns( column_info *col_info )
|
||||
{
|
||||
column_info *c1, *c2;
|
||||
|
||||
/* check for two columns with the same name */
|
||||
for( c1 = col_info; c1; c1 = c1->next )
|
||||
for( c2 = c1->next; c2; c2 = c2->next )
|
||||
if (!lstrcmpW(c1->column, c2->column))
|
||||
return ERROR_BAD_QUERY_SYNTAX;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
||||
column_info *col_info, BOOL temp )
|
||||
{
|
||||
MSICREATEVIEW *cv = NULL;
|
||||
UINT r;
|
||||
|
||||
TRACE("%p\n", cv );
|
||||
|
||||
r = check_columns( col_info );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
||||
cv = msi_alloc_zero( sizeof *cv );
|
||||
if( !cv )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
|
||||
/* fill the structure */
|
||||
cv->view.ops = &create_ops;
|
||||
msiobj_addref( &db->hdr );
|
||||
|
|
|
@ -117,6 +117,31 @@ static BOOL check_execution_scheduling_options(MSIPACKAGE *package, LPCWSTR acti
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* stores the CustomActionData before the action:
|
||||
* [CustomActionData]Action
|
||||
*/
|
||||
LPWSTR msi_get_deferred_action(LPCWSTR action, LPWSTR actiondata)
|
||||
{
|
||||
LPWSTR deferred;
|
||||
DWORD len;
|
||||
|
||||
static const WCHAR begin[] = {'[',0};
|
||||
static const WCHAR end[] = {']',0};
|
||||
|
||||
if (!actiondata)
|
||||
return strdupW(action);
|
||||
|
||||
len = lstrlenW(action) + lstrlenW(actiondata) + 3;
|
||||
deferred = msi_alloc(len * sizeof(WCHAR));
|
||||
|
||||
lstrcpyW(deferred, begin);
|
||||
lstrcatW(deferred, actiondata);
|
||||
lstrcatW(deferred, end);
|
||||
lstrcatW(deferred, action);
|
||||
|
||||
return deferred;
|
||||
}
|
||||
|
||||
UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
|
||||
{
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
|
@ -128,8 +153,18 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
|
|||
'=',' ','\'','%','s','\'',0};
|
||||
UINT type;
|
||||
LPCWSTR source, target;
|
||||
LPWSTR ptr, deferred_data = NULL;
|
||||
LPWSTR action_copy = strdupW(action);
|
||||
WCHAR *deformated=NULL;
|
||||
|
||||
/* deferred action: [CustomActionData]Action */
|
||||
if ((ptr = strchrW(action_copy, ']')))
|
||||
{
|
||||
deferred_data = action_copy + 1;
|
||||
*ptr = '\0';
|
||||
action = ptr + 1;
|
||||
}
|
||||
|
||||
row = MSI_QueryGetRecord( package->db, ExecSeqQuery, action );
|
||||
if (!row)
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
|
@ -160,18 +195,22 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
|
|||
}
|
||||
if (!execute)
|
||||
{
|
||||
LPWSTR actiondata = msi_dup_property(package, action);
|
||||
LPWSTR deferred = msi_get_deferred_action(action, actiondata);
|
||||
|
||||
if (type & msidbCustomActionTypeCommit)
|
||||
{
|
||||
TRACE("Deferring Commit Action!\n");
|
||||
schedule_action(package, COMMIT_SCRIPT, action);
|
||||
schedule_action(package, COMMIT_SCRIPT, deferred);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("Deferring Action!\n");
|
||||
schedule_action(package, INSTALL_SCRIPT, action);
|
||||
schedule_action(package, INSTALL_SCRIPT, deferred);
|
||||
}
|
||||
|
||||
rc = ERROR_SUCCESS;
|
||||
msi_free(deferred);
|
||||
goto end;
|
||||
}
|
||||
else
|
||||
|
@ -182,7 +221,9 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
|
|||
'C','u','s','t','o','m','A','c','t','i','o','n','D','a','t','a',0};
|
||||
static const WCHAR szBlank[] = {0};
|
||||
LPWSTR actiondata = msi_dup_property( package, action );
|
||||
if (actiondata)
|
||||
if (deferred_data)
|
||||
MSI_SetPropertyW(package,szActionData,deferred_data);
|
||||
else if (actiondata)
|
||||
MSI_SetPropertyW(package,szActionData,actiondata);
|
||||
else
|
||||
MSI_SetPropertyW(package,szActionData,szBlank);
|
||||
|
@ -235,6 +276,7 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
|
|||
}
|
||||
|
||||
end:
|
||||
msi_free(action_copy);
|
||||
msiobj_release(&row->hdr);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -63,6 +63,7 @@ struct msi_control_tag
|
|||
HBITMAP hBitmap;
|
||||
HICON hIcon;
|
||||
LPWSTR tabnext;
|
||||
LPWSTR type;
|
||||
HMODULE hDll;
|
||||
float progress_current;
|
||||
float progress_max;
|
||||
|
@ -85,6 +86,7 @@ struct msi_dialog_tag
|
|||
BOOL finished;
|
||||
INT scale;
|
||||
DWORD attributes;
|
||||
SIZE size;
|
||||
HWND hwnd;
|
||||
LPWSTR default_font;
|
||||
msi_font *font_list;
|
||||
|
@ -177,6 +179,18 @@ static msi_control *msi_dialog_find_control( msi_dialog *dialog, LPCWSTR name )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static msi_control *msi_dialog_find_control_by_type( msi_dialog *dialog, LPCWSTR type )
|
||||
{
|
||||
msi_control *control;
|
||||
|
||||
if( !type )
|
||||
return NULL;
|
||||
LIST_FOR_EACH_ENTRY( control, &dialog->controls, msi_control, entry )
|
||||
if( !strcmpW( control->type, type ) ) /* FIXME: case sensitive? */
|
||||
return control;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static msi_control *msi_dialog_find_control_by_hwnd( msi_dialog *dialog, HWND hwnd )
|
||||
{
|
||||
msi_control *control;
|
||||
|
@ -359,6 +373,7 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog,
|
|||
control->hIcon = NULL;
|
||||
control->hDll = NULL;
|
||||
control->tabnext = strdupW( MSI_RecordGetString( rec, 11) );
|
||||
control->type = strdupW( MSI_RecordGetString( rec, 3 ) );
|
||||
control->progress_current = 0;
|
||||
control->progress_max = 100;
|
||||
|
||||
|
@ -393,6 +408,24 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog,
|
|||
return control;
|
||||
}
|
||||
|
||||
static LPWSTR msi_dialog_get_uitext( msi_dialog *dialog, LPCWSTR key )
|
||||
{
|
||||
MSIRECORD *rec;
|
||||
LPWSTR text;
|
||||
|
||||
static const WCHAR query[] = {
|
||||
's','e','l','e','c','t',' ','*',' ',
|
||||
'f','r','o','m',' ','`','U','I','T','e','x','t','`',' ',
|
||||
'w','h','e','r','e',' ','`','K','e','y','`',' ','=',' ','\'','%','s','\'',0
|
||||
};
|
||||
|
||||
rec = MSI_QueryGetRecord( dialog->package->db, query, key );
|
||||
if (!rec) return NULL;
|
||||
text = strdupW( MSI_RecordGetString( rec, 2 ) );
|
||||
msiobj_release( &rec->hdr );
|
||||
return text;
|
||||
}
|
||||
|
||||
static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name )
|
||||
{
|
||||
static const WCHAR query[] = {
|
||||
|
@ -1374,6 +1407,13 @@ static UINT msi_dialog_progress_bar( msi_dialog *dialog, MSIRECORD *rec )
|
|||
|
||||
/******************** Path Edit ********************************************/
|
||||
|
||||
struct msi_pathedit_info
|
||||
{
|
||||
msi_dialog *dialog;
|
||||
msi_control *control;
|
||||
WNDPROC oldproc;
|
||||
};
|
||||
|
||||
static LPWSTR msi_get_window_text( HWND hwnd )
|
||||
{
|
||||
UINT sz, r;
|
||||
|
@ -1393,38 +1433,14 @@ static LPWSTR msi_get_window_text( HWND hwnd )
|
|||
return buf;
|
||||
}
|
||||
|
||||
static UINT msi_dialog_pathedit_handler( msi_dialog *dialog,
|
||||
msi_control *control, WPARAM param )
|
||||
static void msi_dialog_update_pathedit( msi_dialog *dialog, msi_control *control )
|
||||
{
|
||||
LPWSTR buf, prop;
|
||||
BOOL indirect;
|
||||
|
||||
if( HIWORD(param) != EN_KILLFOCUS )
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
indirect = control->attributes & msidbControlAttributesIndirect;
|
||||
prop = msi_dialog_dup_property( dialog, control->property, indirect );
|
||||
|
||||
/* FIXME: verify the new path */
|
||||
buf = msi_get_window_text( control->hwnd );
|
||||
MSI_SetPropertyW( dialog->package, prop, buf );
|
||||
|
||||
TRACE("edit %s contents changed, set %s\n", debugstr_w(control->name),
|
||||
debugstr_w(prop));
|
||||
|
||||
msi_free( buf );
|
||||
msi_free( prop );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static void msi_dialog_update_pathedit( msi_dialog *dialog )
|
||||
{
|
||||
msi_control *control;
|
||||
LPWSTR prop, path;
|
||||
BOOL indirect;
|
||||
|
||||
control = msi_dialog_find_control( dialog, szPathEdit );
|
||||
if (!control && !(control = msi_dialog_find_control_by_type( dialog, szPathEdit )))
|
||||
return;
|
||||
|
||||
indirect = control->attributes & msidbControlAttributesIndirect;
|
||||
prop = msi_dialog_dup_property( dialog, control->property, indirect );
|
||||
|
||||
|
@ -1436,19 +1452,102 @@ static void msi_dialog_update_pathedit( msi_dialog *dialog )
|
|||
msi_free( prop );
|
||||
}
|
||||
|
||||
/* FIXME: test when this should fail */
|
||||
static BOOL msi_dialog_verify_path( LPWSTR path )
|
||||
{
|
||||
if ( !lstrlenW( path ) )
|
||||
return FALSE;
|
||||
|
||||
if ( PathIsRelativeW( path ) )
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* returns TRUE if the path is valid, FALSE otherwise */
|
||||
static BOOL msi_dialog_onkillfocus( msi_dialog *dialog, msi_control *control )
|
||||
{
|
||||
LPWSTR buf, prop;
|
||||
BOOL indirect;
|
||||
BOOL valid;
|
||||
|
||||
indirect = control->attributes & msidbControlAttributesIndirect;
|
||||
prop = msi_dialog_dup_property( dialog, control->property, indirect );
|
||||
|
||||
buf = msi_get_window_text( control->hwnd );
|
||||
|
||||
if ( !msi_dialog_verify_path( buf ) )
|
||||
{
|
||||
/* FIXME: display an error message box */
|
||||
ERR("Invalid path %s\n", debugstr_w( buf ));
|
||||
valid = FALSE;
|
||||
SetFocus( control->hwnd );
|
||||
}
|
||||
else
|
||||
{
|
||||
valid = TRUE;
|
||||
MSI_SetPropertyW( dialog->package, prop, buf );
|
||||
}
|
||||
|
||||
msi_dialog_update_pathedit( dialog, control );
|
||||
|
||||
TRACE("edit %s contents changed, set %s\n", debugstr_w(control->name),
|
||||
debugstr_w(prop));
|
||||
|
||||
msi_free( buf );
|
||||
msi_free( prop );
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
static LRESULT WINAPI MSIPathEdit_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
struct msi_pathedit_info *info = GetPropW(hWnd, szButtonData);
|
||||
LRESULT r = 0;
|
||||
|
||||
TRACE("%p %04x %08x %08lx\n", hWnd, msg, wParam, lParam);
|
||||
|
||||
if ( msg == WM_KILLFOCUS )
|
||||
{
|
||||
/* if the path is invalid, don't handle this message */
|
||||
if ( !msi_dialog_onkillfocus( info->dialog, info->control ) )
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = CallWindowProcW(info->oldproc, hWnd, msg, wParam, lParam);
|
||||
|
||||
if ( msg == WM_NCDESTROY )
|
||||
{
|
||||
msi_free( info );
|
||||
RemovePropW( hWnd, szButtonData );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static UINT msi_dialog_pathedit_control( msi_dialog *dialog, MSIRECORD *rec )
|
||||
{
|
||||
struct msi_pathedit_info *info;
|
||||
msi_control *control;
|
||||
LPCWSTR prop;
|
||||
|
||||
info = msi_alloc( sizeof *info );
|
||||
if (!info)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
control = msi_dialog_add_control( dialog, rec, szEdit,
|
||||
WS_BORDER | WS_TABSTOP );
|
||||
control->handler = msi_dialog_pathedit_handler;
|
||||
control->attributes = MSI_RecordGetInteger( rec, 8 );
|
||||
prop = MSI_RecordGetString( rec, 9 );
|
||||
control->property = msi_dialog_dup_property( dialog, prop, FALSE );
|
||||
|
||||
msi_dialog_update_pathedit( dialog );
|
||||
info->dialog = dialog;
|
||||
info->control = control;
|
||||
info->oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC,
|
||||
(LONG_PTR)MSIPathEdit_WndProc );
|
||||
SetPropW( control->hwnd, szButtonData, info );
|
||||
|
||||
msi_dialog_update_pathedit( dialog, control );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -1961,13 +2060,14 @@ static UINT msi_dialog_list_box( msi_dialog *dialog, MSIRECORD *rec )
|
|||
|
||||
/******************** Directory Combo ***************************************/
|
||||
|
||||
static void msi_dialog_update_directory_combo( msi_dialog *dialog )
|
||||
static void msi_dialog_update_directory_combo( msi_dialog *dialog, msi_control *control )
|
||||
{
|
||||
msi_control *control;
|
||||
LPWSTR prop, path;
|
||||
BOOL indirect;
|
||||
|
||||
control = msi_dialog_find_control( dialog, szDirectoryCombo );
|
||||
if (!control && !(control = msi_dialog_find_control_by_type( dialog, szDirectoryCombo )))
|
||||
return;
|
||||
|
||||
indirect = control->attributes & msidbControlAttributesIndirect;
|
||||
prop = msi_dialog_dup_property( dialog, control->property, indirect );
|
||||
path = msi_dup_property( dialog->package, prop );
|
||||
|
@ -1999,20 +2099,72 @@ static UINT msi_dialog_directory_combo( msi_dialog *dialog, MSIRECORD *rec )
|
|||
prop = MSI_RecordGetString( rec, 9 );
|
||||
control->property = msi_dialog_dup_property( dialog, prop, FALSE );
|
||||
|
||||
msi_dialog_update_directory_combo( dialog );
|
||||
msi_dialog_update_directory_combo( dialog, control );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/******************** Directory List ***************************************/
|
||||
|
||||
static void msi_dialog_update_directory_list( msi_dialog *dialog, msi_control *control )
|
||||
{
|
||||
WCHAR dir_spec[MAX_PATH];
|
||||
WIN32_FIND_DATAW wfd;
|
||||
LPWSTR prop, path;
|
||||
BOOL indirect;
|
||||
LVITEMW item;
|
||||
HANDLE file;
|
||||
|
||||
static const WCHAR asterisk[] = {'*',0};
|
||||
static const WCHAR dot[] = {'.',0};
|
||||
static const WCHAR dotdot[] = {'.','.',0};
|
||||
|
||||
if (!control && !(control = msi_dialog_find_control_by_type( dialog, szDirectoryList )))
|
||||
return;
|
||||
|
||||
/* clear the list-view */
|
||||
SendMessageW( control->hwnd, LVM_DELETEALLITEMS, 0, 0 );
|
||||
|
||||
indirect = control->attributes & msidbControlAttributesIndirect;
|
||||
prop = msi_dialog_dup_property( dialog, control->property, indirect );
|
||||
path = msi_dup_property( dialog->package, prop );
|
||||
|
||||
lstrcpyW( dir_spec, path );
|
||||
lstrcatW( dir_spec, asterisk );
|
||||
|
||||
file = FindFirstFileW( dir_spec, &wfd );
|
||||
if ( file == INVALID_HANDLE_VALUE )
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
if ( wfd.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY )
|
||||
continue;
|
||||
|
||||
if ( !lstrcmpW( wfd.cFileName, dot ) || !lstrcmpW( wfd.cFileName, dotdot ) )
|
||||
continue;
|
||||
|
||||
item.mask = LVIF_TEXT;
|
||||
item.cchTextMax = MAX_PATH;
|
||||
item.iItem = 0;
|
||||
item.iSubItem = 0;
|
||||
item.pszText = wfd.cFileName;
|
||||
|
||||
SendMessageW( control->hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item );
|
||||
} while ( FindNextFileW( file, &wfd ) );
|
||||
|
||||
msi_free( prop );
|
||||
msi_free( path );
|
||||
FindClose( file );
|
||||
}
|
||||
|
||||
UINT msi_dialog_directorylist_up( msi_dialog *dialog )
|
||||
{
|
||||
msi_control *control;
|
||||
LPWSTR prop, path, ptr;
|
||||
BOOL indirect;
|
||||
|
||||
control = msi_dialog_find_control( dialog, szDirectoryList );
|
||||
control = msi_dialog_find_control_by_type( dialog, szDirectoryList );
|
||||
indirect = control->attributes & msidbControlAttributesIndirect;
|
||||
prop = msi_dialog_dup_property( dialog, control->property, indirect );
|
||||
|
||||
|
@ -2025,8 +2177,9 @@ UINT msi_dialog_directorylist_up( msi_dialog *dialog )
|
|||
|
||||
MSI_SetPropertyW( dialog->package, prop, path );
|
||||
|
||||
msi_dialog_update_directory_combo( dialog );
|
||||
msi_dialog_update_pathedit( dialog );
|
||||
msi_dialog_update_directory_list( dialog, NULL );
|
||||
msi_dialog_update_directory_combo( dialog, NULL );
|
||||
msi_dialog_update_pathedit( dialog, NULL );
|
||||
|
||||
msi_free( path );
|
||||
msi_free( prop );
|
||||
|
@ -2034,13 +2187,60 @@ UINT msi_dialog_directorylist_up( msi_dialog *dialog )
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT msi_dialog_dirlist_handler( msi_dialog *dialog,
|
||||
msi_control *control, WPARAM param )
|
||||
{
|
||||
LPNMHDR nmhdr = (LPNMHDR)param;
|
||||
WCHAR new_path[MAX_PATH];
|
||||
WCHAR text[MAX_PATH];
|
||||
LPWSTR path, prop;
|
||||
BOOL indirect;
|
||||
LVITEMW item;
|
||||
int index;
|
||||
|
||||
static const WCHAR backslash[] = {'\\',0};
|
||||
|
||||
if (nmhdr->code != LVN_ITEMACTIVATE)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
index = SendMessageW( control->hwnd, LVM_GETNEXTITEM, -1, LVNI_SELECTED );
|
||||
if ( index < 0 )
|
||||
{
|
||||
ERR("No list-view item selected!\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
item.iSubItem = 0;
|
||||
item.pszText = text;
|
||||
item.cchTextMax = MAX_PATH;
|
||||
SendMessageW( control->hwnd, LVM_GETITEMTEXTW, index, (LPARAM)&item );
|
||||
|
||||
indirect = control->attributes & msidbControlAttributesIndirect;
|
||||
prop = msi_dialog_dup_property( dialog, control->property, indirect );
|
||||
path = msi_dup_property( dialog->package, prop );
|
||||
|
||||
lstrcpyW( new_path, path );
|
||||
lstrcatW( new_path, text );
|
||||
lstrcatW( new_path, backslash );
|
||||
|
||||
MSI_SetPropertyW( dialog->package, prop, new_path );
|
||||
|
||||
msi_dialog_update_directory_list( dialog, NULL );
|
||||
msi_dialog_update_directory_combo( dialog, NULL );
|
||||
msi_dialog_update_pathedit( dialog, NULL );
|
||||
|
||||
msi_free( prop );
|
||||
msi_free( path );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT msi_dialog_directory_list( msi_dialog *dialog, MSIRECORD *rec )
|
||||
{
|
||||
msi_control *control;
|
||||
LPCWSTR prop;
|
||||
DWORD style;
|
||||
|
||||
style = LVS_LIST | LVS_EDITLABELS | WS_VSCROLL | LVS_SHAREIMAGELISTS |
|
||||
style = LVS_LIST | WS_VSCROLL | LVS_SHAREIMAGELISTS |
|
||||
LVS_AUTOARRANGE | LVS_SINGLESEL | WS_BORDER |
|
||||
LVS_SORTASCENDING | WS_CHILD | WS_GROUP | WS_TABSTOP;
|
||||
control = msi_dialog_add_control( dialog, rec, WC_LISTVIEWW, style );
|
||||
|
@ -2048,14 +2248,86 @@ static UINT msi_dialog_directory_list( msi_dialog *dialog, MSIRECORD *rec )
|
|||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
control->attributes = MSI_RecordGetInteger( rec, 8 );
|
||||
control->handler = msi_dialog_dirlist_handler;
|
||||
prop = MSI_RecordGetString( rec, 9 );
|
||||
control->property = msi_dialog_dup_property( dialog, prop, FALSE );
|
||||
|
||||
/* double click to activate an item in the list */
|
||||
SendMessageW( control->hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE,
|
||||
0, LVS_EX_TWOCLICKACTIVATE );
|
||||
|
||||
msi_dialog_update_directory_list( dialog, control );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/******************** VolumeCost List ***************************************/
|
||||
|
||||
static BOOL str_is_number( LPCWSTR str )
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < lstrlenW( str ); i++)
|
||||
if (!isdigitW(str[i]))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WCHAR column_keys[][80] =
|
||||
{
|
||||
{'V','o','l','u','m','e','C','o','s','t','V','o','l','u','m','e',0},
|
||||
{'V','o','l','u','m','e','C','o','s','t','S','i','z','e',0},
|
||||
{'V','o','l','u','m','e','C','o','s','t','A','v','a','i','l','a','b','l','e',0},
|
||||
{'V','o','l','u','m','e','C','o','s','t','R','e','q','u','i','r','e','d',0},
|
||||
{'V','o','l','u','m','e','C','o','s','t','D','i','f','f','e','r','e','n','c','e',0}
|
||||
};
|
||||
|
||||
static void msi_dialog_vcl_add_columns( msi_dialog *dialog, msi_control *control, MSIRECORD *rec )
|
||||
{
|
||||
LPCWSTR text = MSI_RecordGetString( rec, 10 );
|
||||
LPCWSTR begin = text, end;
|
||||
WCHAR num[10];
|
||||
LVCOLUMNW lvc;
|
||||
DWORD count = 0;
|
||||
LRESULT r;
|
||||
|
||||
static const WCHAR zero[] = {'0',0};
|
||||
static const WCHAR negative[] = {'-',0};
|
||||
|
||||
while ((begin = strchrW( begin, '{' )) && count < 5)
|
||||
{
|
||||
if (!(end = strchrW( begin, '}' )))
|
||||
return;
|
||||
|
||||
lstrcpynW( num, begin + 1, end - begin );
|
||||
begin += end - begin + 1;
|
||||
|
||||
/* empty braces or '0' hides the column */
|
||||
if ( !num[0] || !lstrcmpW( num, zero ) )
|
||||
{
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* the width must be a positive number
|
||||
* if a width is invalid, all remaining columns are hidden
|
||||
*/
|
||||
if ( !strncmpW( num, negative, 1 ) || !str_is_number( num ) )
|
||||
return;
|
||||
|
||||
lvc.mask = LVCF_FMT | LVCF_ORDER | LVCF_WIDTH | LVCF_TEXT;
|
||||
lvc.iOrder = count;
|
||||
lvc.pszText = msi_dialog_get_uitext( dialog, column_keys[count++] );
|
||||
lvc.cx = atolW( num );
|
||||
lvc.fmt = LVCFMT_LEFT;
|
||||
|
||||
r = SendMessageW( control->hwnd, LVM_INSERTCOLUMNW, 0, (LPARAM)&lvc );
|
||||
msi_free( lvc.pszText );
|
||||
if ( r ) return;
|
||||
}
|
||||
}
|
||||
|
||||
static UINT msi_dialog_volumecost_list( msi_dialog *dialog, MSIRECORD *rec )
|
||||
{
|
||||
msi_control *control;
|
||||
|
@ -2068,6 +2340,8 @@ static UINT msi_dialog_volumecost_list( msi_dialog *dialog, MSIRECORD *rec )
|
|||
if (!control)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
msi_dialog_vcl_add_columns( dialog, control, rec );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -2292,10 +2566,27 @@ static void msi_dialog_adjust_dialog_pos( msi_dialog *dialog, MSIRECORD *rec, LP
|
|||
center.y = MulDiv( center.y, yres, 100 );
|
||||
|
||||
/* turn the client pos into the window rectangle */
|
||||
pos->left = center.x - sz.cx/2;
|
||||
pos->right = pos->left + sz.cx;
|
||||
pos->top = center.y - sz.cy/2;
|
||||
pos->bottom = pos->top + sz.cy;
|
||||
if (dialog->package->center_x && dialog->package->center_y)
|
||||
{
|
||||
pos->left = dialog->package->center_x - sz.cx / 2.0;
|
||||
pos->right = pos->left + sz.cx;
|
||||
pos->top = dialog->package->center_y - sz.cy / 2.0;
|
||||
pos->bottom = pos->top + sz.cy;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos->left = center.x - sz.cx/2;
|
||||
pos->right = pos->left + sz.cx;
|
||||
pos->top = center.y - sz.cy/2;
|
||||
pos->bottom = pos->top + sz.cy;
|
||||
|
||||
/* save the center */
|
||||
dialog->package->center_x = center.x;
|
||||
dialog->package->center_y = center.y;
|
||||
}
|
||||
|
||||
dialog->size.cx = sz.cx;
|
||||
dialog->size.cy = sz.cy;
|
||||
|
||||
TRACE("%lu %lu %lu %lu\n", pos->left, pos->top, pos->right, pos->bottom);
|
||||
|
||||
|
@ -2609,6 +2900,19 @@ static LRESULT msi_dialog_oncommand( msi_dialog *dialog, WPARAM param, HWND hwnd
|
|||
return 0;
|
||||
}
|
||||
|
||||
static LRESULT msi_dialog_onnotify( msi_dialog *dialog, LPARAM param )
|
||||
{
|
||||
LPNMHDR nmhdr = (LPNMHDR) param;
|
||||
msi_control *control = msi_dialog_find_control_by_hwnd( dialog, nmhdr->hwndFrom );
|
||||
|
||||
TRACE("%p %p", dialog, nmhdr->hwndFrom);
|
||||
|
||||
if ( control && control->handler )
|
||||
control->handler( dialog, control, param );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void msi_dialog_setfocus( msi_dialog *dialog )
|
||||
{
|
||||
HWND hwnd = dialog->hWndFocus;
|
||||
|
@ -2628,6 +2932,11 @@ static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg,
|
|||
|
||||
switch (msg)
|
||||
{
|
||||
case WM_MOVE:
|
||||
dialog->package->center_x = LOWORD(lParam) + dialog->size.cx / 2.0;
|
||||
dialog->package->center_y = HIWORD(lParam) + dialog->size.cy / 2.0;
|
||||
break;
|
||||
|
||||
case WM_CREATE:
|
||||
return msi_dialog_oncreate( hwnd, (LPCREATESTRUCTW)lParam );
|
||||
|
||||
|
@ -2652,6 +2961,8 @@ static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg,
|
|||
case WM_DESTROY:
|
||||
dialog->hwnd = NULL;
|
||||
return 0;
|
||||
case WM_NOTIFY:
|
||||
return msi_dialog_onnotify( dialog, lParam );
|
||||
}
|
||||
return DefWindowProcW(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
@ -2861,6 +3172,7 @@ void msi_dialog_destroy( msi_dialog *dialog )
|
|||
if( t->hIcon )
|
||||
DestroyIcon( t->hIcon );
|
||||
msi_free( t->tabnext );
|
||||
msi_free( t->type );
|
||||
msi_free( t );
|
||||
if (t->hDll)
|
||||
FreeLibrary( t->hDll );
|
||||
|
|
|
@ -50,19 +50,53 @@ static LPWSTR build_default_format(MSIRECORD* record)
|
|||
{
|
||||
int i;
|
||||
int count;
|
||||
LPWSTR rc;
|
||||
static const WCHAR fmt[] = {'%','i',':',' ','[','%','i',']',' ',0};
|
||||
WCHAR buf[11];
|
||||
LPWSTR rc, buf;
|
||||
static const WCHAR fmt[] = {'%','i',':',' ','%','s',' ',0};
|
||||
static const WCHAR fmt_null[] = {'%','i',':',' ',' ',0};
|
||||
static const WCHAR fmt_index[] = {'%','i',0};
|
||||
LPCWSTR str;
|
||||
WCHAR index[10];
|
||||
DWORD size, max_len, len;
|
||||
|
||||
count = MSI_RecordGetFieldCount(record);
|
||||
|
||||
rc = msi_alloc((11*count)*sizeof(WCHAR));
|
||||
rc[0] = 0;
|
||||
max_len = MAX_PATH;
|
||||
buf = msi_alloc((max_len + 1) * sizeof(WCHAR));
|
||||
|
||||
rc = NULL;
|
||||
size = 1;
|
||||
for (i = 1; i <= count; i++)
|
||||
{
|
||||
sprintfW(buf,fmt,i,i);
|
||||
strcatW(rc,buf);
|
||||
sprintfW(index,fmt_index,i);
|
||||
str = MSI_RecordGetString(record, i);
|
||||
len = (str) ? lstrlenW(str) : 0;
|
||||
len += (sizeof(fmt_null) - 3) + lstrlenW(index);
|
||||
size += len;
|
||||
|
||||
if (len > max_len)
|
||||
{
|
||||
max_len = len;
|
||||
buf = msi_realloc(buf, (max_len + 1) * sizeof(WCHAR));
|
||||
if (!buf) return NULL;
|
||||
}
|
||||
|
||||
if (str)
|
||||
sprintfW(buf,fmt,i,str);
|
||||
else
|
||||
sprintfW(buf,fmt_null,i);
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
rc = msi_alloc(size * sizeof(WCHAR));
|
||||
lstrcpyW(rc, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = msi_realloc(rc, size * sizeof(WCHAR));
|
||||
lstrcatW(rc, buf);
|
||||
}
|
||||
}
|
||||
msi_free(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -131,8 +165,8 @@ static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz,
|
|||
{
|
||||
ERR("Unable to get ShortPath size (%s)\n",
|
||||
debugstr_w( file->TargetPath) );
|
||||
value = NULL;
|
||||
*sz = 0;
|
||||
value = strdupW( file->TargetPath );
|
||||
*sz = (lstrlenW(value)) * sizeof(WCHAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,6 @@ static MSIRECORD *INSERT_merge_record( UINT fields, column_info *vl, MSIRECORD *
|
|||
{
|
||||
MSIRECORD *merged;
|
||||
DWORD wildcard_count = 1, i;
|
||||
const WCHAR *str;
|
||||
|
||||
merged = MSI_CreateRecord( fields );
|
||||
for( i=1; i <= fields; i++ )
|
||||
|
@ -88,10 +87,7 @@ static MSIRECORD *INSERT_merge_record( UINT fields, column_info *vl, MSIRECORD *
|
|||
case EXPR_WILDCARD:
|
||||
if( !rec )
|
||||
goto err;
|
||||
if( MSI_RecordIsNull( rec, wildcard_count ) )
|
||||
goto err;
|
||||
str = MSI_RecordGetString( rec, wildcard_count );
|
||||
MSI_RecordSetStringW( merged, i, str );
|
||||
MSI_RecordCopyField( rec, wildcard_count, merged, i );
|
||||
wildcard_count++;
|
||||
break;
|
||||
default:
|
||||
|
@ -238,6 +234,14 @@ static const MSIVIEWOPS insert_ops =
|
|||
INSERT_find_matching_rows
|
||||
};
|
||||
|
||||
static UINT count_column_info( column_info *ci )
|
||||
{
|
||||
UINT n = 0;
|
||||
for ( ; ci; ci = ci->next )
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
||||
column_info *columns, column_info *values, BOOL temp )
|
||||
{
|
||||
|
@ -247,6 +251,10 @@ UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
|||
|
||||
TRACE("%p\n", iv );
|
||||
|
||||
/* there should be one value for each column */
|
||||
if ( count_column_info( columns ) != count_column_info(values) )
|
||||
return ERROR_BAD_QUERY_SYNTAX;
|
||||
|
||||
r = TABLE_CreateView( db, table, &tv );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
@ -258,7 +266,7 @@ UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
|||
tv->ops->delete( tv );
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
iv = msi_alloc_zero( sizeof *iv );
|
||||
if( !iv )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
|
|
@ -364,7 +364,7 @@ static const MSIVIEWOPS join_ops =
|
|||
*/
|
||||
static UINT join_check_condition(MSIJOINVIEW *jv, struct expr *cond)
|
||||
{
|
||||
UINT r, type = 0;
|
||||
UINT r;
|
||||
|
||||
/* assume that we have `KeyColumn` = `SubkeyColumn` */
|
||||
if ( cond->type != EXPR_COMPLEX )
|
||||
|
@ -388,21 +388,6 @@ static UINT join_check_condition(MSIJOINVIEW *jv, struct expr *cond)
|
|||
if (r != ERROR_SUCCESS)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
/* make sure both columns are keys */
|
||||
r = jv->left->ops->get_column_info( jv->left, jv->left_key, NULL, &type );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
if (!(type & MSITYPE_KEY))
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = jv->right->ops->get_column_info( jv->right, jv->right_key, NULL, &type );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
if (!(type & MSITYPE_KEY))
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
TRACE("left %s (%u) right %s (%u)\n",
|
||||
debugstr_w(cond->u.expr.left->u.column), jv->left_key,
|
||||
debugstr_w(cond->u.expr.right->u.column), jv->right_key);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -231,6 +231,8 @@ typedef struct tagMSIPACKAGE
|
|||
UINT CurrentInstallState;
|
||||
msi_dialog *dialog;
|
||||
LPWSTR next_dialog;
|
||||
float center_x;
|
||||
float center_y;
|
||||
|
||||
UINT WordCount;
|
||||
|
||||
|
@ -334,8 +336,6 @@ extern const WCHAR *msi_string_lookup_id( string_table *st, UINT id );
|
|||
extern UINT msi_string_get_codepage( string_table *st );
|
||||
|
||||
|
||||
extern UINT VIEW_find_column( MSIVIEW *view, LPCWSTR name, UINT *n );
|
||||
|
||||
extern BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name );
|
||||
|
||||
extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname,
|
||||
|
@ -371,6 +371,7 @@ extern UINT MSI_RecordSetStreamW( MSIRECORD *, unsigned int, LPCWSTR );
|
|||
extern UINT MSI_RecordSetStreamA( MSIRECORD *, unsigned int, LPCSTR );
|
||||
extern UINT MSI_RecordDataSize( MSIRECORD *, unsigned int );
|
||||
extern UINT MSI_RecordStreamToFile( MSIRECORD *, unsigned int, LPCWSTR );
|
||||
extern UINT MSI_RecordCopyField( MSIRECORD *, unsigned int, MSIRECORD *, unsigned int );
|
||||
|
||||
/* stream internals */
|
||||
extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm );
|
||||
|
@ -392,6 +393,9 @@ extern UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *, LPCWSTR, MSIRECORD ** );
|
|||
extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * );
|
||||
extern UINT MSI_ViewFetch( MSIQUERY*, MSIRECORD ** );
|
||||
extern UINT MSI_ViewClose( MSIQUERY* );
|
||||
extern UINT MSI_ViewGetColumnInfo(MSIQUERY *, MSICOLINFO, MSIRECORD **);
|
||||
extern UINT VIEW_find_column( MSIVIEW *, LPCWSTR, UINT * );
|
||||
|
||||
|
||||
/* install internals */
|
||||
extern UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel );
|
||||
|
|
|
@ -480,48 +480,28 @@ static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field, UINT type )
|
|||
return MSI_RecordSetStringW( rec, field, szType );
|
||||
}
|
||||
|
||||
UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
|
||||
UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
|
||||
{
|
||||
MSIVIEW *view = NULL;
|
||||
MSIQUERY *query = NULL;
|
||||
MSIRECORD *rec = NULL;
|
||||
UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
|
||||
MSIRECORD *rec;
|
||||
MSIVIEW *view = query->view;
|
||||
LPWSTR name;
|
||||
|
||||
TRACE("%ld %d %p\n", hView, info, hRec);
|
||||
|
||||
if( !hRec )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
|
||||
if( !query )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
view = query->view;
|
||||
if( !view )
|
||||
goto out;
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
if( !view->ops->get_dimensions )
|
||||
goto out;
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = view->ops->get_dimensions( view, NULL, &count );
|
||||
if( r )
|
||||
goto out;
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
if( !count )
|
||||
{
|
||||
r = ERROR_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
rec = MSI_CreateRecord( count );
|
||||
if( !rec )
|
||||
{
|
||||
r = ERROR_FUNCTION_FAILED;
|
||||
goto out;
|
||||
}
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
for( i=0; i<count; i++ )
|
||||
{
|
||||
|
@ -536,14 +516,38 @@ UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hR
|
|||
msi_free( name );
|
||||
}
|
||||
|
||||
*hRec = alloc_msihandle( &rec->hdr );
|
||||
if (! *hRec)
|
||||
r = ERROR_NOT_ENOUGH_MEMORY;
|
||||
*prec = rec;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
out:
|
||||
msiobj_release( &query->hdr );
|
||||
if( rec )
|
||||
UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
|
||||
{
|
||||
MSIQUERY *query = NULL;
|
||||
MSIRECORD *rec = NULL;
|
||||
UINT r;
|
||||
|
||||
TRACE("%ld %d %p\n", hView, info, hRec);
|
||||
|
||||
if( !hRec )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
|
||||
if( !query )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
r = MSI_ViewGetColumnInfo( query, info, &rec );
|
||||
if ( r == ERROR_SUCCESS )
|
||||
{
|
||||
*hRec = alloc_msihandle( &rec->hdr );
|
||||
if ( !*hRec )
|
||||
r = ERROR_NOT_ENOUGH_MEMORY;
|
||||
msiobj_release( &rec->hdr );
|
||||
}
|
||||
|
||||
msiobj_release( &query->hdr );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
|||
|
||||
#define MSIFIELD_NULL 0
|
||||
#define MSIFIELD_INT 1
|
||||
#define MSIFIELD_STR 2
|
||||
#define MSIFIELD_WSTR 3
|
||||
#define MSIFIELD_STREAM 4
|
||||
|
||||
|
@ -154,6 +153,53 @@ static BOOL string2intW( LPCWSTR str, int *out )
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
UINT MSI_RecordCopyField( MSIRECORD *in_rec, unsigned int in_n,
|
||||
MSIRECORD *out_rec, unsigned int out_n )
|
||||
{
|
||||
UINT r = ERROR_SUCCESS;
|
||||
|
||||
msiobj_lock( &in_rec->hdr );
|
||||
|
||||
if ( in_n > in_rec->count || out_n > out_rec->count )
|
||||
r = ERROR_FUNCTION_FAILED;
|
||||
else if ( in_rec != out_rec || in_n != out_n )
|
||||
{
|
||||
LPWSTR str;
|
||||
MSIFIELD *in, *out;
|
||||
|
||||
in = &in_rec->fields[in_n];
|
||||
out = &out_rec->fields[out_n];
|
||||
|
||||
switch ( in->type )
|
||||
{
|
||||
case MSIFIELD_NULL:
|
||||
break;
|
||||
case MSIFIELD_INT:
|
||||
out->u.iVal = in->u.iVal;
|
||||
break;
|
||||
case MSIFIELD_WSTR:
|
||||
str = strdupW( in->u.szwVal );
|
||||
if ( !str )
|
||||
r = ERROR_OUTOFMEMORY;
|
||||
else
|
||||
out->u.szwVal = str;
|
||||
break;
|
||||
case MSIFIELD_STREAM:
|
||||
IStream_AddRef( in->u.stream );
|
||||
out->u.stream = in->u.stream;
|
||||
break;
|
||||
default:
|
||||
ERR("invalid field type %d\n", in->type);
|
||||
}
|
||||
if (r == ERROR_SUCCESS)
|
||||
out->type = in->type;
|
||||
}
|
||||
|
||||
msiobj_unlock( &in_rec->hdr );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int MSI_RecordGetInteger( MSIRECORD *rec, unsigned int iField)
|
||||
{
|
||||
int ret = 0;
|
||||
|
|
|
@ -102,13 +102,34 @@ static UINT SELECT_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT va
|
|||
static UINT SELECT_insert_row( struct tagMSIVIEW *view, MSIRECORD *record )
|
||||
{
|
||||
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
|
||||
UINT i, table_cols, r;
|
||||
MSIRECORD *outrec;
|
||||
|
||||
TRACE("%p %p\n", sv, record );
|
||||
|
||||
if( !sv->table )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
if ( !sv->table )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
return sv->table->ops->insert_row( sv->table, record );
|
||||
/* rearrange the record to suit the table */
|
||||
r = sv->table->ops->get_dimensions( sv->table, NULL, &table_cols );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
outrec = MSI_CreateRecord( table_cols + 1 );
|
||||
|
||||
for (i=0; i<sv->num_cols; i++)
|
||||
{
|
||||
r = MSI_RecordCopyField( record, i+1, outrec, sv->cols[i] );
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sv->table->ops->insert_row( sv->table, outrec );
|
||||
|
||||
fail:
|
||||
msiobj_release( &outrec->hdr );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static UINT SELECT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
|
||||
|
|
|
@ -108,7 +108,7 @@ static struct expr * EXPR_wildcard( void *info );
|
|||
%token TK_ROW TK_RP TK_RSHIFT
|
||||
%token TK_SELECT TK_SEMI TK_SET TK_SHORT TK_SLASH TK_SPACE TK_STAR TK_STATEMENT
|
||||
%token <str> TK_STRING
|
||||
%token TK_TABLE TK_TEMP TK_THEN TK_TRANSACTION TK_TRIGGER
|
||||
%token TK_TABLE TK_TEMPORARY TK_THEN TK_TRANSACTION TK_TRIGGER
|
||||
%token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE
|
||||
%token TK_UPDATE TK_UPLUS TK_USING
|
||||
%token TK_VACUUM TK_VALUES TK_VIEW
|
||||
|
@ -171,7 +171,7 @@ oneinsert:
|
|||
YYABORT;
|
||||
$$ = insert;
|
||||
}
|
||||
| TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMP
|
||||
| TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMPORARY
|
||||
{
|
||||
SQL_input *sql = (SQL_input*) info;
|
||||
MSIVIEW *insert = NULL;
|
||||
|
@ -304,6 +304,10 @@ column_type:
|
|||
{
|
||||
$$ = $1 | MSITYPE_LOCALIZABLE;
|
||||
}
|
||||
| data_type_l TK_TEMPORARY
|
||||
{
|
||||
FIXME("temporary column\n");
|
||||
}
|
||||
;
|
||||
|
||||
data_type_l:
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
#define HASH_SIZE 67
|
||||
#define HASH_SIZE 0x101
|
||||
|
||||
typedef struct _msistring
|
||||
{
|
||||
|
|
|
@ -926,20 +926,7 @@ static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count )
|
|||
|
||||
LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid)
|
||||
{
|
||||
UINT sz=0, r;
|
||||
LPWSTR str;
|
||||
|
||||
r = msi_id2stringW( db->strings, stringid, NULL, &sz );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return NULL;
|
||||
str = msi_alloc( sz*sizeof (WCHAR) );
|
||||
if( !str )
|
||||
return str;
|
||||
r = msi_id2stringW( db->strings, stringid, str, &sz );
|
||||
if( r == ERROR_SUCCESS )
|
||||
return str;
|
||||
msi_free( str );
|
||||
return NULL;
|
||||
return strdupW(msi_string_lookup_id( db->strings, stringid ));
|
||||
}
|
||||
|
||||
static UINT get_tablecolumns( MSIDATABASE *db,
|
||||
|
@ -1116,7 +1103,7 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt
|
|||
{
|
||||
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
|
||||
UINT ival = 0, refcol = 0, r;
|
||||
LPWSTR sval;
|
||||
LPCWSTR sval;
|
||||
LPWSTR full_name;
|
||||
DWORD len;
|
||||
static const WCHAR szDot[] = { '.', 0 };
|
||||
|
@ -1140,7 +1127,7 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt
|
|||
return r;
|
||||
|
||||
/* lookup the string value from the string table */
|
||||
sval = MSI_makestring( tv->db, refcol );
|
||||
sval = msi_string_lookup_id( tv->db->strings, refcol );
|
||||
if( !sval )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
|
@ -1154,7 +1141,6 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt
|
|||
if( r )
|
||||
ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r);
|
||||
msi_free( full_name );
|
||||
msi_free( sval );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -1302,12 +1288,38 @@ static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row );
|
|||
|
||||
static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec )
|
||||
{
|
||||
UINT r, row;
|
||||
UINT r, row, i;
|
||||
|
||||
/* check there's no null values where they're not allowed */
|
||||
for( i = 0; i < tv->num_cols; i++ )
|
||||
{
|
||||
if ( tv->columns[i].type & MSITYPE_NULLABLE )
|
||||
continue;
|
||||
|
||||
if ( tv->columns[i].type & MSITYPE_STRING )
|
||||
{
|
||||
LPCWSTR str;
|
||||
|
||||
str = MSI_RecordGetString( rec, i+1 );
|
||||
if (str == NULL || str[0] == 0)
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT n;
|
||||
|
||||
n = MSI_RecordGetInteger( rec, i+1 );
|
||||
if (n == MSI_NULL_INTEGER)
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
/* check there's no duplicate keys */
|
||||
r = msi_table_find_row( tv, rec, &row );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return ERROR_SUCCESS;
|
||||
return ERROR_INVALID_DATA;
|
||||
if (r == ERROR_SUCCESS)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT msi_table_modify_row( MSITABLEVIEW *tv, MSIRECORD *rec,
|
||||
|
@ -1352,6 +1364,11 @@ static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec )
|
|||
|
||||
TRACE("%p %p\n", tv, rec );
|
||||
|
||||
/* check that the key is unique - can we find a matching row? */
|
||||
r = table_validate_new( tv, rec );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = table_create_new_row( view, &row );
|
||||
TRACE("insert_row returned %08x\n", r);
|
||||
if( r != ERROR_SUCCESS )
|
||||
|
|
|
@ -39,6 +39,8 @@ struct Keyword {
|
|||
int tokenType; /* The token value for this keyword */
|
||||
};
|
||||
|
||||
#define MAX_TOKEN_LEN 11
|
||||
|
||||
static const WCHAR ABORT_W[] = { 'A','B','O','R','T',0 };
|
||||
static const WCHAR AFTER_W[] = { 'A','F','T','E','R',0 };
|
||||
static const WCHAR ALTER_W[] = { 'A','L','T','E','R',0 };
|
||||
|
@ -245,8 +247,7 @@ static const Keyword aKeywordTable[] = {
|
|||
{ SHORT_W, TK_SHORT },
|
||||
{ STATEMENT_W, TK_STATEMENT },
|
||||
{ TABLE_W, TK_TABLE },
|
||||
{ TEMP_W, TK_TEMP },
|
||||
{ TEMPORARY_W, TK_TEMP },
|
||||
/*{ TEMPORARY_W, TK_TEMPORARY },*/
|
||||
{ THEN_W, TK_THEN },
|
||||
{ TRANSACTION_W, TK_TRANSACTION },
|
||||
{ TRIGGER_W, TK_TRIGGER },
|
||||
|
@ -263,21 +264,34 @@ static const Keyword aKeywordTable[] = {
|
|||
|
||||
#define KEYWORD_COUNT ( sizeof aKeywordTable/sizeof (Keyword) )
|
||||
|
||||
/*
|
||||
** Comparison function for binary search.
|
||||
*/
|
||||
static int compKeyword(const void *m1, const void *m2){
|
||||
const Keyword *k1 = m1, *k2 = m2;
|
||||
|
||||
return strcmpiW( k1->zName, k2->zName );
|
||||
}
|
||||
|
||||
/*
|
||||
** This function looks up an identifier to determine if it is a
|
||||
** keyword. If it is a keyword, the token code of that keyword is
|
||||
** returned. If the input is not a keyword, TK_ID is returned.
|
||||
*/
|
||||
static int sqliteKeywordCode(const WCHAR *z, int n){
|
||||
UINT i;
|
||||
WCHAR str[MAX_TOKEN_LEN+1];
|
||||
Keyword key, *r;
|
||||
|
||||
for(i=0; i<KEYWORD_COUNT; i++)
|
||||
{
|
||||
if(strncmpiW(z, aKeywordTable[i].zName, n))
|
||||
continue;
|
||||
if(lstrlenW(aKeywordTable[i].zName) == n )
|
||||
return aKeywordTable[i].tokenType;
|
||||
}
|
||||
if( n>MAX_TOKEN_LEN )
|
||||
return TK_ID;
|
||||
|
||||
memcpy( str, z, n*sizeof (WCHAR) );
|
||||
str[n] = 0;
|
||||
key.tokenType = 0;
|
||||
key.zName = str;
|
||||
r = bsearch( &key, aKeywordTable, KEYWORD_COUNT, sizeof (Keyword), compKeyword );
|
||||
if( r )
|
||||
return r->tokenType;
|
||||
return TK_ID;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue