dialog.c

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

C
2,228
字号
        arg = MSI_RecordGetString( rec, 4 );
        if( event[0] == '[' )
            msi_dialog_set_property( dialog, event, arg );
        else
            msi_dialog_send_event( dialog, event, arg );
    }

    return ERROR_SUCCESS;
}

static UINT msi_dialog_button_handler( msi_dialog *dialog,
                                       msi_control *control, WPARAM param )
{
    static const WCHAR query[] = {
      'S','E','L','E','C','T',' ','*',' ',
      'F','R','O','M',' ','C','o','n','t','r','o','l','E','v','e','n','t',' ',
      'W','H','E','R','E',' ',
         '`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',' ',
      'A','N','D',' ',
         '`','C','o','n','t','r','o','l','_','`',' ','=',' ','\'','%','s','\'',' ',
      'O','R','D','E','R',' ','B','Y',' ','`','O','r','d','e','r','i','n','g','`',0
    };
    MSIQUERY *view = NULL;
    UINT r;

    if( HIWORD(param) != BN_CLICKED )
        return ERROR_SUCCESS;

    r = MSI_OpenQuery( dialog->package->db, &view, query,
                       dialog->name, control->name );
    if( r != ERROR_SUCCESS )
    {
        ERR("query failed\n");
        return 0;
    }

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

    return r;
}

static UINT msi_dialog_get_checkbox_state( msi_dialog *dialog,
                msi_control *control )
{
    WCHAR state[2] = { 0 };
    DWORD sz = 2;

    MSI_GetPropertyW( dialog->package, control->property, state, &sz );
    return state[0] ? 1 : 0;
}

static void msi_dialog_set_checkbox_state( msi_dialog *dialog,
                msi_control *control, UINT state )
{
    static const WCHAR szState[] = { '1', 0 };
    LPCWSTR val;

    /* if uncheck then the property is set to NULL */
    if (!state)
    {
        MSI_SetPropertyW( dialog->package, control->property, NULL );
        return;
    }

    /* check for a custom state */
    if (control->value && control->value[0])
        val = control->value;
    else
        val = szState;

    MSI_SetPropertyW( dialog->package, control->property, val );
}

static void msi_dialog_checkbox_sync_state( msi_dialog *dialog,
                msi_control *control )
{
    UINT state;

    state = msi_dialog_get_checkbox_state( dialog, control );
    SendMessageW( control->hwnd, BM_SETCHECK,
                  state ? BST_CHECKED : BST_UNCHECKED, 0 );
}

static UINT msi_dialog_checkbox_handler( msi_dialog *dialog,
                msi_control *control, WPARAM param )
{
    UINT state;

    if( HIWORD(param) != BN_CLICKED )
        return ERROR_SUCCESS;

    TRACE("clicked checkbox %s, set %s\n", debugstr_w(control->name),
          debugstr_w(control->property));

    state = msi_dialog_get_checkbox_state( dialog, control );
    state = state ? 0 : 1;
    msi_dialog_set_checkbox_state( dialog, control, state );
    msi_dialog_checkbox_sync_state( dialog, control );

    return msi_dialog_button_handler( dialog, control, param );
}

static UINT msi_dialog_edit_handler( msi_dialog *dialog,
                msi_control *control, WPARAM param )
{
    UINT sz, r;
    LPWSTR buf;

    if( HIWORD(param) != EN_CHANGE )
        return ERROR_SUCCESS;

    TRACE("edit %s contents changed, set %s\n", debugstr_w(control->name),
          debugstr_w(control->property));

    sz = 0x20;
    buf = msi_alloc( sz*sizeof(WCHAR) );
    while( buf )
    {
        r = GetWindowTextW( control->hwnd, buf, sz );
        if( r < (sz-1) )
            break;
        sz *= 2;
        buf = msi_realloc( buf, sz*sizeof(WCHAR) );
    }

    MSI_SetPropertyW( dialog->package, control->property, buf );

    msi_free( buf );

    return ERROR_SUCCESS;
}

static UINT msi_dialog_radiogroup_handler( msi_dialog *dialog,
                msi_control *control, WPARAM param )
{
    if( HIWORD(param) != BN_CLICKED )
        return ERROR_SUCCESS;

    TRACE("clicked radio button %s, set %s\n", debugstr_w(control->name),
          debugstr_w(control->property));

    MSI_SetPropertyW( dialog->package, control->property, control->name );

    return msi_dialog_button_handler( dialog, control, param );
}

static LRESULT msi_dialog_oncommand( msi_dialog *dialog, WPARAM param, HWND hwnd )
{
    msi_control *control = NULL;

    TRACE("%p %p %08x\n", dialog, hwnd, param);

    switch (param)
    {
    case 1: /* enter */
        control = msi_dialog_find_control( dialog, dialog->control_default );
        break;
    case 2: /* escape */
        control = msi_dialog_find_control( dialog, dialog->control_cancel );
        break;
    default: 
        control = msi_dialog_find_control_by_hwnd( dialog, hwnd );
    }

    if( control )
    {
        if( control->handler )
        {
            control->handler( dialog, control, param );
            msi_dialog_evaluate_control_conditions( dialog );
        }
    }
    else
        ERR("button click from nowhere %p %d %p\n", dialog, param, hwnd);
    return 0;
}

static void msi_dialog_setfocus( msi_dialog *dialog )
{
    HWND hwnd = dialog->hWndFocus;

    hwnd = GetNextDlgTabItem( dialog->hwnd, hwnd, TRUE);
    hwnd = GetNextDlgTabItem( dialog->hwnd, hwnd, FALSE);
    SetFocus( hwnd );
    dialog->hWndFocus = hwnd;
}

static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg,
                WPARAM wParam, LPARAM lParam )
{
    msi_dialog *dialog = (LPVOID) GetWindowLongPtrW( hwnd, GWLP_USERDATA );

    TRACE("0x%04x\n", msg);

    switch (msg)
    {
    case WM_CREATE:
        return msi_dialog_oncreate( hwnd, (LPCREATESTRUCTW)lParam );

    case WM_COMMAND:
        return msi_dialog_oncommand( dialog, wParam, (HWND)lParam );

    case WM_ACTIVATE:
        if( LOWORD(wParam) == WA_INACTIVE )
            dialog->hWndFocus = GetFocus();
        else
            msi_dialog_setfocus( dialog );
        return 0;

    case WM_SETFOCUS:
        msi_dialog_setfocus( dialog );
        return 0;

    /* bounce back to our subclassed static control */
    case WM_CTLCOLORSTATIC:
        return SendMessageW( (HWND) lParam, WM_CTLCOLORSTATIC, wParam, lParam );

    case WM_DESTROY:
        dialog->hwnd = NULL;
        return 0;
    }
    return DefWindowProcW(hwnd, msg, wParam, lParam);
}

static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    WNDPROC oldproc = (WNDPROC) GetPropW(hWnd, szButtonData);

    TRACE("hWnd %p msg %04x wParam 0x%08x lParam 0x%08lx\n", hWnd, msg, wParam, lParam);

    if (msg == WM_COMMAND) /* Forward notifications to dialog */
        SendMessageW(GetParent(hWnd), msg, wParam, lParam);

    return CallWindowProcW(oldproc, hWnd, msg, wParam, lParam);
}

static LRESULT WINAPI MSIHiddenWindowProc( HWND hwnd, UINT msg,
                WPARAM wParam, LPARAM lParam )
{
    msi_dialog *dialog = (msi_dialog*) lParam;

    TRACE("%d %p\n", msg, dialog);

    switch (msg)
    {
    case WM_MSI_DIALOG_CREATE:
        return msi_dialog_run_message_loop( dialog );
    case WM_MSI_DIALOG_DESTROY:
        msi_dialog_destroy( dialog );
        return 0;
    }
    return DefWindowProcW( hwnd, msg, wParam, lParam );
}

/* functions that interface to other modules within MSI */

msi_dialog *msi_dialog_create( MSIPACKAGE* package, LPCWSTR szDialogName,
                                msi_dialog_event_handler event_handler )
{
    MSIRECORD *rec = NULL;
    msi_dialog *dialog;

    TRACE("%p %s\n", package, debugstr_w(szDialogName));

    /* allocate the structure for the dialog to use */
    dialog = msi_alloc_zero( sizeof *dialog + sizeof(WCHAR)*strlenW(szDialogName) );
    if( !dialog )
        return NULL;
    strcpyW( dialog->name, szDialogName );
    msiobj_addref( &package->hdr );
    dialog->package = package;
    dialog->event_handler = event_handler;
    dialog->finished = 0;
    list_init( &dialog->controls );

    /* verify that the dialog exists */
    rec = msi_get_dialog_record( dialog );
    if( !rec )
    {
        msiobj_release( &package->hdr );
        msi_free( dialog );
        return NULL;
    }
    dialog->attributes = MSI_RecordGetInteger( rec, 6 );
    dialog->control_default = strdupW( MSI_RecordGetString( rec, 9 ) );
    dialog->control_cancel = strdupW( MSI_RecordGetString( rec, 10 ) );
    msiobj_release( &rec->hdr );

    return dialog;
}

static void msi_process_pending_messages( HWND hdlg )
{
    MSG msg;

    while( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ) )
    {
        if( hdlg && IsDialogMessageW( hdlg, &msg ))
            continue;
        TranslateMessage( &msg );
        DispatchMessageW( &msg );
    }
}

void msi_dialog_end_dialog( msi_dialog *dialog )
{
    TRACE("%p\n", dialog);
    dialog->finished = 1;
    PostMessageW(dialog->hwnd, WM_NULL, 0, 0);
}

void msi_dialog_check_messages( HANDLE handle )
{
    DWORD r;

    /* in threads other than the UI thread, block */
    if( uiThreadId != GetCurrentThreadId() )
    {
        if( handle )
            WaitForSingleObject( handle, INFINITE );
        return;
    }

    /* there's two choices for the UI thread */
    while (1)
    {
        msi_process_pending_messages( NULL );

        if( !handle )
            break;

        /*
         * block here until somebody creates a new dialog or
         * the handle we're waiting on becomes ready
         */
        r = MsgWaitForMultipleObjects( 1, &handle, 0, INFINITE, QS_ALLINPUT );
        if( r == WAIT_OBJECT_0 )
            break;
    }
}

UINT msi_dialog_run_message_loop( msi_dialog *dialog )
{
    HWND hwnd;

    if( !(dialog->attributes & msidbDialogAttributesVisible) )
        return ERROR_SUCCESS;

    if( uiThreadId != GetCurrentThreadId() )
        return SendMessageW( hMsiHiddenWindow, WM_MSI_DIALOG_CREATE, 0, (LPARAM) dialog );

    /* create the dialog window, don't show it yet */
    hwnd = CreateWindowW( szMsiDialogClass, dialog->name, WS_OVERLAPPEDWINDOW,
                     CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                     NULL, NULL, NULL, dialog );
    if( !hwnd )
    {
        ERR("Failed to create dialog %s\n", debugstr_w( dialog->name ));
        return ERROR_FUNCTION_FAILED;
    }

    ShowWindow( hwnd, SW_SHOW );
    /* UpdateWindow( hwnd ); - and causes the transparent static controls not to paint */

    if( dialog->attributes & msidbDialogAttributesModal )
    {
        while( !dialog->finished )
        {
            MsgWaitForMultipleObjects( 0, NULL, 0, INFINITE, QS_ALLEVENTS );
            msi_process_pending_messages( dialog->hwnd );
        }
    }
    else
        return ERROR_IO_PENDING;

    return ERROR_SUCCESS;
}

void msi_dialog_do_preview( msi_dialog *dialog )
{
    TRACE("\n");
    dialog->attributes |= msidbDialogAttributesVisible;
    dialog->attributes &= ~msidbDialogAttributesModal;
    msi_dialog_run_message_loop( dialog );
}

void msi_dialog_destroy( msi_dialog *dialog )
{
    if( uiThreadId != GetCurrentThreadId() )
    {
        SendMessageW( hMsiHiddenWindow, WM_MSI_DIALOG_DESTROY, 0, (LPARAM) dialog );
        return;
    }

    if( dialog->hwnd )
        ShowWindow( dialog->hwnd, SW_HIDE );
    
    if( dialog->hwnd )
        DestroyWindow( dialog->hwnd );

    /* destroy the list of controls */
    while( !list_empty( &dialog->controls ) )
    {
        msi_control *t = LIST_ENTRY( list_head( &dialog->controls ),
                                     msi_control, entry );
        list_remove( &t->entry );
        /* leave dialog->hwnd - destroying parent destroys child windows */
        msi_free( t->property );
        msi_free( t->value );
        if( t->hBitmap )
            DeleteObject( t->hBitmap );
        if( t->hIcon )
            DestroyIcon( t->hIcon );
        msi_free( t->tabnext );
        msi_free( t );
    }

    /* destroy the list of fonts */
    while( dialog->font_list )
    {
        msi_font *t = dialog->font_list;
        dialog->font_list = t->next;
        DeleteObject( t->hfont );
        msi_free( t );
    }
    msi_free( dialog->default_font );

    msi_free( dialog->control_default );
    msi_free( dialog->control_cancel );
    msiobj_release( &dialog->package->hdr );
    dialog->package = NULL;
    msi_free( dialog );
}

BOOL msi_dialog_register_class( void )
{
    WNDCLASSW cls;

    ZeroMemory( &cls, sizeof cls );
    cls.lpfnWndProc   = MSIDialog_WndProc;
    cls.hInstance     = NULL;
    cls.hIcon         = LoadIconW(0, (LPWSTR)IDI_APPLICATION);
    cls.hCursor       = LoadCursorW(0, (LPWSTR)IDC_ARRO

⌨️ 快捷键说明

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