The Bard of Chelsea
The Bard of Chelsea

Reputation: 45

c++ Dialog box doesn't render properly on PC screen

I have dialog window specified via a *.rc file that doesn't render properly on the screen. It exhibits the following set of anomalies:

  1. The dialog window is white.
  2. The dialog window title bar is absent.
  3. All GUI objects are rendered two times -- once at position (X,Y) specified by the *.rc file and a 2nd time at position (X+3,Y+23). Pushbuttons at position (X,Y) are alive. The "echoes" at (X+3,Y+23) are non-functional.
  4. The pushbutton object specified as DEFPUSHBUTTON is not the default pushbutton, and the pushbutton object specified as PUSHBUTTON is the default pushbutton.

Other than the default pushbutton anomaly and the weird appearance, the Dialog window operates as it should, as does the callback function -- SelectPuzzle() -- that it invokes. The source code for SelectPuzzle() is not enclosed but is available upon request as are screen shots.

This code is virtually identical to code I have used successfully in other projects. Why it doesn't work here remains a mystery. Can anyone help?

I've tried everything I can think of to diagnose this bug but without success, e.g.:

  1. In place of DialogBoxParam(), I tried using DialogBox() with variable PuzzleDB supplied as a global. Same result.
  2. I tried stripped-down, simplified versions both of the resource file and of the SelectPuzzle() function, -- i.e., a DIALOGEX resource with just a "Cancel" pushbutton and a SelectPuzzle() function with just an empty WM_INITDIALOG section and a WM_COMMAND case to support the Cancel pushbutton. Same result.
  3. I verified consistent use of the IDD_SELECTPUZZLE constant in MainApp and in resource file. I also tried different numeric values for IDD_SELECTPUZZLE.
    Same result.

The following code excerpts are relevant:

MainApp.h    (included in stdafx.h)                                                      
  .                                                                                      
  .                                                                                          
#define IDD_SELECTPUZZLE   9500                                                              
#define IDM_SelectPuzzle   9510                                                              
#define ID_CurrentPuzzle   9521                                                              
#define ID_SelectedPuzzle  9522                                                              
#define ID_PuzzleSelStatus 9523                                                              
  .                                                                                      
  .                                                                                                                                                                                   

PuzzleDB.h   (included in stdafx.h)                                                      

//=======================================================================                
// PuzzleDB.h : Defines the entry point for the application.                             
//=======================================================================                    
#pragma once                                                                             

typedef struct {                                                                             
    int NumberOfPuzzles;                                                                        
    int *PuzzleNumbers;                                                                         
    int ndxCurrentPuzzleNumber;                                                                   
    clasPuzzle *Puzzle;                                                                         
} PuzzleSelectionData, *pPuzzleSelectionData;                                                

clasPuzzle *ResetPuzzle(                                                                     
    clasPuzzle *Puzzle                                                                          
  );    

char *LoadPuzzle(                                                                            
    char *tstr                                                                                   
  , int ndxSelectedPuzzle                                                                      
  , pPuzzleSelectionData pPuzzleDB );                                                                                     


MainApp.cpp,                                                                             

#include "stdafx.h"                                                                          
  .                                                                                      
  .                                                                                            
LRESULT CALLBACK  WndProc(HWND, UINT, WPARAM, LPARAM);                                       
INT_PTR CALLBACK  SelectPuzzle(HWND, UINT, WPARAM, LPARAM);                                  
  .                                                                                      
  .                                                                                            
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)              
  .                                                                                      
  .                                                                                            
  static PuzzleSelectionData PuzzleDB;                                                         
  .                                                                                      
  .                                                                                            
  switch (message)                                                                             
  .                                                                                      
  .                                                                                            
    case WM_COMMAND:                                                                             
      switch (wParam)                                                                      
  .                                                                                      
  .                                                                                            
        //*****WM_COMMAND********************************************            
        case IDM_SelectPuzzle:                                                                       
          k = PuzzleDB.ndxCurrentPuzzleNumber;                                                         
          DialogBoxParam(                                                                              
              hInst                                                                                        
            , MAKEINTRESOURCE(IDD_SELECTPUZZLE)        
            , hWnd, SelectPuzzle                                                                         
            , (unsigned long)(&PuzzleDB));                                                               
          if (PuzzleDB.ndxCurrentPuzzleNumber != k)                                                    
            SendMessage(hWnd,WM_COMMAND,IDM_LoadPuzzle,0L);                              
          break;                                                                         
  .                                                                                      
  .                                                                                                                                                                                  
AppName.rc                                                                               
  .                                                                                     
  .                                                                                      
//**** BEGIN Application specific resources *********************************            
 //--------------------------------------------------------------------------------       
// Application specific resource.                                                        
// Menu Dialog item "Select Puzzle"                                                      
//--------------------------------------------------------------------------------       
IDD_SELECTPUZZLE DIALOGEX 4, 4, 126, 74 // Position w.r.t. parent window.                
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU      
CAPTION "Select Puzzle"                                                                  
FONT 10, "MS Shell Dlg"                                                                  
BEGIN                                                                                    
  ICON            IDR_MAINFRAME             , IDC_STATIC        ,14,14, 21,20            
  LTEXT "Use Mouse Wheel to Select Puzzle." , IDC_STATIC        , 8, 4,118,12,SS_NOPREFIX
  LTEXT           "Current Puzzle:  "       , IDC_STATIC        , 8,16, 52,12,SS_NOPREFIX
  LTEXT           "New Selection:   "       , IDC_STATIC        , 8,28, 52,12,SS_NOPREFIX
  PUSHBUTTON      "Accept"                  , ID_OK             , 8,40, 52, 4,WS_GROUP   
  DEFPUSHBUTTON   "CANCEL"                  , ID_CANCEL         ,66,40, 52, 4,WS_GROUP   
  LTEXT           "                 "       , ID_CurrentPuzzle  ,66,16, 52,12,SS_NOPREFIX
  LTEXT           "                 "       , ID_SelectedPuzzle ,66,28, 52,12,SS_NOPREFIX
  LTEXT           "                 "       , ID_PuzzleSelStatus, 8,60,110,12,SS_NOPREFIX
  END                                                                                    
//**** END Application specific resources ***********************************            

Upvotes: 1

Views: 722

Answers (1)

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145389

The main problem is that you return TRUE from the dialog procedure for all messages. Except for a handful of special messages, this indicates that you don't want default handling. Thus things that should be done, are not being done.

Tip for dialogs: seriously underdocumented, but where you need to return some specific value for some specific message, use SetDlgMsgResult from <windowsx.h>, or equivalent code.


In passing, the code can be greatly simplified and improved by

  • removing use of Visual C++ non-standard semantics precompiled headers (for standard-conformance and maintainability),

  • removing use of Visual C++ non-standard tWinMain, just use standard main,

  • removing use of Windows 9x support (the unmentionably silly Microsoft T stuff for strings),

  • using std::wstring instead of C library string handling,

  • and using wide string literals instead of narrow ones plus conversion,

  • etc.


A particularly bad apple, in the tWinMain function this code:

  if (!InitInstance (hInstance, nCmdShow))
  {
    return FALSE;
  }
  1. InitInstance only makes sense for 16-bit Windows.

  2. passing nCmdShow around only makes sense for 16-bit Windows (in 32-bit Windows it is ignored by the first ShowWindow call).

  3. Returning FALSE here erroneously indicates success, when it is a failure.

I have seen essentially this code many times, even in the D language's Windows support, and I suspect that it originates with Microsoft.

Anyway, wherever you got that from, that source is seriously outdated and unreliable, to be treated only as a source of bad programming habits and ingenious ways to introduce bugs.

Upvotes: 1

Related Questions