MSI: Radio Buttons

Ulrich Czekalla ulrich.czekalla at utoronto.ca
Thu Mar 3 07:59:51 CST 2005


On Thu, Mar 03, 2005 at 12:42:53PM +0100, Alexandre Julliard wrote:
> Ulrich Czekalla <ulrich.czekalla at utoronto.ca> writes:
> 
> >  const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
> > +const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
> > +
> > +const static WCHAR szButtonData = { 0 };
> 
> Did you really intend to use an empty string here for the button
> property?  That doesn't seem right; though if you really need to

I was just making sure you still review all the patches ;-) New patch
resubmitted.

> redefine the winproc it would be much cleaner IMO to define a proper
> window class.
> 

Checking using spy++ MSI does just subclass the button class.

Thanks,

/Ulrich
-------------- next part --------------
Index: dlls/msi/dialog.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/dialog.c,v
retrieving revision 1.6
diff -u -p -r1.6 dialog.c
--- dlls/msi/dialog.c	16 Feb 2005 16:25:36 -0000	1.6
+++ dlls/msi/dialog.c	3 Mar 2005 13:57:23 -0000
@@ -41,6 +41,9 @@ const WCHAR szMsiDialogClass[] = {
     'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0
 };
 const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
+const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
+
+const static WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 };
 
 struct msi_control_tag;
 typedef struct msi_control_tag msi_control;
@@ -83,10 +86,19 @@ struct control_handler 
     msi_dialog_control_func func;
 };
 
+typedef struct
+{
+    msi_dialog* dialog;
+    msi_control *parent;
+    DWORD       attributes;
+} radio_button_group_descr;
+
 static UINT msi_dialog_checkbox_handler( msi_dialog *, msi_control *, WPARAM );
 static void msi_dialog_checkbox_sync_state( msi_dialog *, msi_control * );
 static UINT msi_dialog_button_handler( msi_dialog *, msi_control *, WPARAM );
 static UINT msi_dialog_edit_handler( msi_dialog *, msi_control *, WPARAM );
+static UINT msi_dialog_radiogroup_handler( msi_dialog *, msi_control *, WPARAM param );
+static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
 
 
 INT msi_dialog_scale_unit( msi_dialog *dialog, INT val )
@@ -275,7 +287,6 @@ static UINT msi_dialog_text_control( msi
 
 static UINT msi_dialog_button_control( msi_dialog *dialog, MSIRECORD *rec )
 {
-    const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
     msi_control *control;
 
     TRACE("%p %p\n", dialog, rec);
@@ -288,7 +299,6 @@ static UINT msi_dialog_button_control( m
 
 static UINT msi_dialog_checkbox_control( msi_dialog *dialog, MSIRECORD *rec )
 {
-    const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
     msi_control *control;
     LPCWSTR prop;
 
@@ -367,17 +377,119 @@ static UINT msi_dialog_pathedit_control(
     return msi_dialog_edit_control( dialog, rec );
 }
 
-static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec )
+static UINT msi_dialog_create_radiobutton( MSIRECORD *rec, LPVOID param )
 {
-    LPCWSTR name;
+    radio_button_group_descr *group = (radio_button_group_descr *)param;
+    msi_dialog *dialog = group->dialog;
+    msi_control *control;
+    LPCWSTR prop;
+    DWORD x, y, width, height, style;
+    DWORD attributes = group->attributes;
+    LPCWSTR text, name;
+    LPWSTR font = NULL, title = NULL;
+
+    style = WS_CHILD | BS_AUTORADIOBUTTON | BS_MULTILINE;
+    name = MSI_RecordGetString( rec, 3 );
+    control = HeapAlloc( GetProcessHeap(), 0,
+                         sizeof *control + strlenW(name)*sizeof(WCHAR) );
+    strcpyW( control->name, name );
+    control->next = dialog->control_list;
+    dialog->control_list = control;
+
+    x = MSI_RecordGetInteger( rec, 4 );
+    y = MSI_RecordGetInteger( rec, 5 );
+    width = MSI_RecordGetInteger( rec, 6 );
+    height = MSI_RecordGetInteger( rec, 7 );
+    text = MSI_RecordGetString( rec, 8 );
+
+    x = msi_dialog_scale_unit( dialog, x );
+    y = msi_dialog_scale_unit( dialog, y );
+    width = msi_dialog_scale_unit( dialog, width );
+    height = msi_dialog_scale_unit( dialog, height );
+
+    if( attributes & 1 )
+        style |= WS_VISIBLE;
+    if( ~attributes & 2 )
+        style |= WS_DISABLED;
+
+    if( text )
+    {
+        font = msi_dialog_get_style( &text );
+        deformat_string( dialog->package, text, &title );
+    }
+
+    control->hwnd = CreateWindowW( szButton, title, style, x, y, width, height,
+        group->parent->hwnd, NULL, NULL, NULL );
+
+    TRACE("Dialog %s control %s hwnd %p\n", debugstr_w(dialog->name), debugstr_w(text), control->hwnd);
+
+    msi_dialog_set_font( dialog, control->hwnd,
+            font ? font : dialog->default_font );
+
+    HeapFree( GetProcessHeap(), 0, font );
+    HeapFree( GetProcessHeap(), 0, title );
+
+    control->handler = msi_dialog_radiogroup_handler;
+
+    prop = MSI_RecordGetString( rec, 1 );
+    if( prop )
+        control->property = dupstrW( prop );
 
-    name = MSI_RecordGetString( rec, 2 );
-    FIXME("Radio group %s\n", debugstr_w( name ) );
     return ERROR_SUCCESS;
 }
 
+static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec )
+{
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','*',' ',
+        'F','R','O','M',' ','R','a','d','i','o','B','u','t','t','o','n',' ',
+        'W','H','E','R','E',' ',
+           '`','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
+    UINT r;
+    LPCWSTR prop;
+    msi_control *control;
+    MSIQUERY *view = NULL;
+    radio_button_group_descr group;
+    MSIPACKAGE *package = dialog->package;
+
+    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 );
+
+    if (control->hwnd)
+    {
+        WNDPROC oldproc = (WNDPROC) SetWindowLongW(control->hwnd, GWLP_WNDPROC,
+            (LONG)MSIRadioGroup_WndProc);
+        SetPropW(control->hwnd, szButtonData, oldproc);
+    }
+
+    if( prop )
+        control->property = dupstrW( 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;
+}
+
 static const WCHAR szText[] = { 'T','e','x','t',0 };
-static const WCHAR szButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 };
+static const WCHAR szPushButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 };
 static const WCHAR szLine[] = { 'L','i','n','e',0 };
 static const WCHAR szBitmap[] = { 'B','i','t','m','a','p',0 };
 static const WCHAR szCheckBox[] = { 'C','h','e','c','k','B','o','x',0 };
@@ -393,7 +505,7 @@ static const WCHAR szRadioButtonGroup[] 
 struct control_handler msi_dialog_handler[] =
 {
     { szText, msi_dialog_text_control },
-    { szButton, msi_dialog_button_control },
+    { szPushButton, msi_dialog_button_control },
     { szLine, msi_dialog_line_control },
     { szBitmap, msi_dialog_bitmap_control },
     { szCheckBox, msi_dialog_checkbox_control },
@@ -811,6 +923,20 @@ static UINT msi_dialog_edit_handler( msi
     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;
@@ -836,6 +962,7 @@ static LRESULT WINAPI MSIDialog_WndProc(
 {
     msi_dialog *dialog = (LPVOID) GetWindowLongPtrW( hwnd, GWLP_USERDATA );
 
+    TRACE(" 0x%04x\n", msg);
     switch (msg)
     {
     case WM_CREATE:
@@ -990,4 +1117,16 @@ void msi_dialog_register_class( void )
 void msi_dialog_unregister_class( void )
 {
     UnregisterClassW( szMsiDialogClass, NULL );
+}
+
+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);
 }


More information about the wine-patches mailing list