dialog.c

来自「一个类似windows」· C语言 代码 · 共 2,228 行 · 第 1/5 页

C
2,228
字号
    msi_control *control;
    MSIQUERY *view = NULL;
    radio_button_group_descr group;
    MSIPACKAGE *package = dialog->package;
    WNDPROC oldproc;

    prop = MSI_RecordGetString( rec, 9 );

    TRACE("%p %p %s\n", dialog, rec, debugstr_w( prop ));

    /* Create parent group box to hold radio buttons */
    control = msi_dialog_add_control( dialog, rec, szButton, BS_OWNERDRAW|WS_GROUP );
    if( !control )
        return ERROR_FUNCTION_FAILED;

    oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC,
                                           (LONG_PTR)MSIRadioGroup_WndProc );
    SetPropW(control->hwnd, szButtonData, oldproc);
    SetWindowLongPtrW( control->hwnd, GWL_EXSTYLE, WS_EX_CONTROLPARENT );

    if( prop )
        control->property = strdupW( prop );

    /* query the Radio Button table for all control in this group */
    r = MSI_OpenQuery( package->db, &view, query, prop );
    if( r != ERROR_SUCCESS )
    {
        ERR("query failed for dialog %s radio group %s\n", 
            debugstr_w(dialog->name), debugstr_w(prop));
        return ERROR_INVALID_PARAMETER;
    }

    group.dialog = dialog;
    group.parent = control;
    group.attributes = MSI_RecordGetInteger( rec, 8 );

    r = MSI_IterateRecords( view, 0, msi_dialog_create_radiobutton, &group );
    msiobj_release( &view->hdr );

    return r;
}

/******************** Selection Tree ***************************************/

static void
msi_dialog_tv_add_child_features( MSIPACKAGE *package, HWND hwnd,
                                  LPCWSTR parent, HTREEITEM hParent )
{
    MSIFEATURE *feature;
    TVINSERTSTRUCTW tvis;
    HTREEITEM hitem;

    LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
    {
        if ( lstrcmpW( parent, feature->Feature_Parent ) )
            continue;

        if ( !feature->Title )
            continue;

        memset( &tvis, 0, sizeof tvis );
        tvis.hParent = hParent;
        tvis.hInsertAfter = TVI_SORT;
        if (feature->Title)
        {
            tvis.u.item.mask = TVIF_TEXT;
            tvis.u.item.pszText = feature->Title;
        }
        tvis.u.item.lParam = (LPARAM) feature;
        hitem = (HTREEITEM) SendMessageW( hwnd, TVM_INSERTITEMW, 0, (LPARAM) &tvis );
        if (!hitem)
            continue;

        msi_dialog_tv_add_child_features( package, hwnd,
                                          feature->Feature, hitem );
    }
}

static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec )
{
    msi_control *control;
    LPCWSTR prop;
    LPWSTR val;
    MSIPACKAGE *package = dialog->package;

    prop = MSI_RecordGetString( rec, 9 );
    val = msi_dup_property( package, prop );
    control = msi_dialog_add_control( dialog, rec, WC_TREEVIEWW,
                                      TVS_HASBUTTONS | WS_GROUP | WS_VSCROLL );
    if (!control)
        return ERROR_FUNCTION_FAILED;

    msi_dialog_tv_add_child_features( package, control->hwnd, NULL, NULL );

    msi_free( val );

    return ERROR_SUCCESS;
}

struct control_handler msi_dialog_handler[] =
{
    { szText, msi_dialog_text_control },
    { szPushButton, msi_dialog_button_control },
    { szLine, msi_dialog_line_control },
    { szBitmap, msi_dialog_bitmap_control },
    { szCheckBox, msi_dialog_checkbox_control },
    { szScrollableText, msi_dialog_scrolltext_control },
    { szComboBox, msi_dialog_combo_control },
    { szEdit, msi_dialog_edit_control },
    { szMaskedEdit, msi_dialog_maskedit_control },
    { szPathEdit, msi_dialog_pathedit_control },
    { szProgressBar, msi_dialog_progress_bar },
    { szRadioButtonGroup, msi_dialog_radiogroup_control },
    { szIcon, msi_dialog_icon_control },
    { szSelectionTree, msi_dialog_selection_tree },
};

#define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0])

static UINT msi_dialog_create_controls( MSIRECORD *rec, LPVOID param )
{
    msi_dialog *dialog = param;
    LPCWSTR control_type;
    UINT i;

    /* find and call the function that can create this type of control */
    control_type = MSI_RecordGetString( rec, 3 );
    for( i=0; i<NUM_CONTROL_TYPES; i++ )
        if (!strcmpiW( msi_dialog_handler[i].control_type, control_type ))
            break;
    if( i != NUM_CONTROL_TYPES )
        msi_dialog_handler[i].func( dialog, rec );
    else
        ERR("no handler for element type %s\n", debugstr_w(control_type));

    return ERROR_SUCCESS;
}

static UINT msi_dialog_fill_controls( msi_dialog *dialog )
{
    static const WCHAR query[] = {
        'S','E','L','E','C','T',' ','*',' ',
        'F','R','O','M',' ','C','o','n','t','r','o','l',' ',
        'W','H','E','R','E',' ',
           '`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',0};
    UINT r;
    MSIQUERY *view = NULL;
    MSIPACKAGE *package = dialog->package;

    TRACE("%p %s\n", dialog, debugstr_w(dialog->name) );

    /* query the Control table for all the elements of the control */
    r = MSI_OpenQuery( package->db, &view, query, dialog->name );
    if( r != ERROR_SUCCESS )
    {
        ERR("query failed for dialog %s\n", debugstr_w(dialog->name));
        return ERROR_INVALID_PARAMETER;
    }

    r = MSI_IterateRecords( view, 0, msi_dialog_create_controls, dialog );
    msiobj_release( &view->hdr );

    return r;
}

static UINT msi_dialog_set_control_condition( MSIRECORD *rec, LPVOID param )
{
    static const WCHAR szHide[] = { 'H','i','d','e',0 };
    static const WCHAR szShow[] = { 'S','h','o','w',0 };
    static const WCHAR szDisable[] = { 'D','i','s','a','b','l','e',0 };
    static const WCHAR szEnable[] = { 'E','n','a','b','l','e',0 };
    msi_dialog *dialog = param;
    msi_control *control;
    LPCWSTR name, action, condition;
    UINT r;

    name = MSI_RecordGetString( rec, 2 );
    action = MSI_RecordGetString( rec, 3 );
    condition = MSI_RecordGetString( rec, 4 );
    r = MSI_EvaluateConditionW( dialog->package, condition );
    control = msi_dialog_find_control( dialog, name );
    if( r == MSICONDITION_TRUE && control )
    {
        TRACE("%s control %s\n", debugstr_w(action), debugstr_w(name));

        /* FIXME: case sensitive? */
        if(!lstrcmpW(action, szHide))
            ShowWindow(control->hwnd, SW_HIDE);
        else if(!strcmpW(action, szShow))
            ShowWindow(control->hwnd, SW_SHOW);
        else if(!strcmpW(action, szDisable))
            EnableWindow(control->hwnd, FALSE);
        else if(!strcmpW(action, szEnable))
            EnableWindow(control->hwnd, TRUE);
        else
            FIXME("Unhandled action %s\n", debugstr_w(action));
    }

    return ERROR_SUCCESS;
}

static UINT msi_dialog_evaluate_control_conditions( msi_dialog *dialog )
{
    static const WCHAR query[] = {
      'S','E','L','E','C','T',' ','*',' ',
      'F','R','O','M',' ',
        'C','o','n','t','r','o','l','C','o','n','d','i','t','i','o','n',' ',
      'W','H','E','R','E',' ',
        '`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',0
    };
    UINT r;
    MSIQUERY *view = NULL;
    MSIPACKAGE *package = dialog->package;

    TRACE("%p %s\n", dialog, debugstr_w(dialog->name) );

    /* query the Control table for all the elements of the control */
    r = MSI_OpenQuery( package->db, &view, query, dialog->name );
    if( r != ERROR_SUCCESS )
    {
        ERR("query failed for dialog %s\n", debugstr_w(dialog->name));
        return ERROR_INVALID_PARAMETER;
    }

    r = MSI_IterateRecords( view, 0, msi_dialog_set_control_condition, dialog );
    msiobj_release( &view->hdr );

    return r;
}

UINT msi_dialog_reset( msi_dialog *dialog )
{
    /* FIXME: should restore the original values of any properties we changed */
    return msi_dialog_evaluate_control_conditions( dialog );
}

/* figure out the height of 10 point MS Sans Serif */
static INT msi_dialog_get_sans_serif_height( HWND hwnd )
{
    static const WCHAR szSansSerif[] = {
        'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0 };
    LOGFONTW lf;
    TEXTMETRICW tm;
    BOOL r;
    LONG height = 0;
    HFONT hFont, hOldFont;
    HDC hdc;

    hdc = GetDC( hwnd );
    if (hdc)
    {
        memset( &lf, 0, sizeof lf );
        lf.lfHeight = MulDiv(10, GetDeviceCaps(hdc, LOGPIXELSY), 72);
        strcpyW( lf.lfFaceName, szSansSerif );
        hFont = CreateFontIndirectW(&lf);
        if (hFont)
        {
            hOldFont = SelectObject( hdc, hFont );
            r = GetTextMetricsW( hdc, &tm );
            if (r)
                height = tm.tmHeight;
            SelectObject( hdc, hOldFont );
            DeleteObject( hFont );
        }
        ReleaseDC( hwnd, hdc );
    }
    return height;
}

/* fetch the associated record from the Dialog table */
static MSIRECORD *msi_get_dialog_record( msi_dialog *dialog )
{
    static const WCHAR query[] = {
        'S','E','L','E','C','T',' ','*',' ',
        'F','R','O','M',' ','D','i','a','l','o','g',' ',
        'W','H','E','R','E',' ',
           '`','D','i','a','l','o','g','`',' ','=',' ','\'','%','s','\'',0};
    MSIPACKAGE *package = dialog->package;
    MSIRECORD *rec = NULL;

    TRACE("%p %s\n", dialog, debugstr_w(dialog->name) );

    rec = MSI_QueryGetRecord( package->db, query, dialog->name );
    if( !rec )
        ERR("query failed for dialog %s\n", debugstr_w(dialog->name));

    return rec;
}

static void msi_dialog_adjust_dialog_size( msi_dialog *dialog, LPSIZE sz )
{
    RECT rect;
    LONG style;

    /* turn the client size into the window rectangle */
    rect.left = 0;
    rect.top = 0;
    rect.right = msi_dialog_scale_unit( dialog, sz->cx );
    rect.bottom = msi_dialog_scale_unit( dialog, sz->cy );
    style = GetWindowLongPtrW( dialog->hwnd, GWL_STYLE );
    AdjustWindowRect( &rect, style, FALSE );
    sz->cx = rect.right - rect.left;
    sz->cy = rect.bottom - rect.top;
}

static BOOL msi_control_set_next( msi_control *control, msi_control *next )
{
    return SetWindowPos( next->hwnd, control->hwnd, 0, 0, 0, 0,
                         SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREDRAW |
                         SWP_NOREPOSITION | SWP_NOSENDCHANGING | SWP_NOSIZE );
}

static UINT msi_dialog_set_tab_order( msi_dialog *dialog )
{
    msi_control *control, *tab_next;

    LIST_FOR_EACH_ENTRY( control, &dialog->controls, msi_control, entry )
    {
        tab_next = msi_dialog_find_control( dialog, control->tabnext );
        if( !tab_next )
            continue;
        msi_control_set_next( control, tab_next );
    }

    return ERROR_SUCCESS;
}

static void msi_dialog_set_first_control( msi_dialog* dialog, LPCWSTR name )
{
    msi_control *control;

    control = msi_dialog_find_control( dialog, name );
    if( control )
        dialog->hWndFocus = control->hwnd;
    else
        dialog->hWndFocus = NULL;
}

static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs )
{
    static const WCHAR df[] = {
        'D','e','f','a','u','l','t','U','I','F','o','n','t',0 };
    static const WCHAR dfv[] = {
        'M','S',' ','S','h','e','l','l',' ','D','l','g',0 };
    msi_dialog *dialog = (msi_dialog*) cs->lpCreateParams;
    MSIRECORD *rec = NULL;
    LPWSTR title = NULL;
    SIZE size;

    TRACE("%p %p\n", dialog, dialog->package);

    dialog->hwnd = hwnd;
    SetWindowLongPtrW( hwnd, GWLP_USERDATA, (LONG_PTR) dialog );

    rec = msi_get_dialog_record( dialog );
    if( !rec )
    {
        TRACE("No record found for dialog %s\n", debugstr_w(dialog->name));
        return -1;
    }

    dialog->scale = msi_dialog_get_sans_serif_height(dialog->hwnd);

    size.cx = MSI_RecordGetInteger( rec, 4 );
    size.cy = MSI_RecordGetInteger( rec, 5 );
    msi_dialog_adjust_dialog_size( dialog, &size );

    dialog->attributes = MSI_RecordGetInteger( rec, 6 );

    dialog->default_font = msi_dup_property( dialog->package, df );
    if (!dialog->default_font)
    {
        dialog->default_font = strdupW(dfv);
        if (!dialog->default_font) return -1;
    }

    title = msi_get_deformatted_field( dialog->package, rec, 7 );
    SetWindowTextW( hwnd, title );
    msi_free( title );

    SetWindowPos( hwnd, 0, 0, 0, size.cx, size.cy,
                  SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW );


    msi_dialog_build_font_list( dialog );
    msi_dialog_fill_controls( dialog );
    msi_dialog_evaluate_control_conditions( dialog );
    msi_dialog_set_tab_order( dialog );
    msi_dialog_set_first_control( dialog, MSI_RecordGetString( rec, 8 ) );
    msiobj_release( &rec->hdr );

    return 0;
}

static UINT msi_dialog_send_event( msi_dialog *dialog, LPCWSTR event, LPCWSTR arg )
{
    LPWSTR event_fmt = NULL, arg_fmt = NULL;

    TRACE("Sending control event %s %s\n", debugstr_w(event), debugstr_w(arg));

    deformat_string( dialog->package, event, &event_fmt );
    deformat_string( dialog->package, arg, &arg_fmt );

    dialog->event_handler( dialog->package, event_fmt, arg_fmt, dialog );

    msi_free( event_fmt );
    msi_free( arg_fmt );

    return ERROR_SUCCESS;
}

static UINT msi_dialog_set_property( msi_dialog *dialog, LPCWSTR event, LPCWSTR arg )
{
    static const WCHAR szNullArg[] = { '{','}',0 };
    LPWSTR p, prop, arg_fmt = NULL;
    UINT len;

    len = strlenW(event);
    prop = msi_alloc( len*sizeof(WCHAR));
    strcpyW( prop, &event[1] );
    p = strchrW( prop, ']' );
    if( p && p[1] == 0 )
    {
        *p = 0;
        if( strcmpW( szNullArg, arg ) )
            deformat_string( dialog->package, arg, &arg_fmt );
        MSI_SetPropertyW( dialog->package, prop, arg_fmt );
        msi_free( arg_fmt );
    }
    else
        ERR("Badly formatted property string - what happens?\n");
    msi_free( prop );
    return ERROR_SUCCESS;
}

static UINT msi_dialog_control_event( MSIRECORD *rec, LPVOID param )
{
    msi_dialog *dialog = param;
    LPCWSTR condition, event, arg;
    UINT r;

    condition = MSI_RecordGetString( rec, 5 );
    r = MSI_EvaluateConditionW( dialog->package, condition );
    if( r == MSICONDITION_TRUE )
    {
        event = MSI_RecordGetString( rec, 3 );

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?