Tutorial 10: Caja de Diálogo [Dialog Box] como Ventana Principal

Ahora viene la parte realmente interesante sobre GUI, la caja de diálogo. En este tutorial (y en el próximo), aprenderemos como podemos usar una caja de diálogo como programa principal.

Bajar el primer ejemplo aquí, el segundo ejemplo aquí.

Teoría:

Si juegas bastante con los ejemplos del tutorial anterior, encontrarás que no puedes cambiar el foco de entrada de un control de ventana hija a otra con la tecla Tab. La única manera de realizar eso es haciendo click sobre el control que deseas que gane el foco de entrada. Esta situación es más bien incómoda. Otra cosa que deberías notar es que cambié el color del fondo de la ventana padre a gris en vez de a blanco, como lo había hecho en los ejemplos previos. Esto se hace así para que el color de la ventana hija pueda armonizar con el color del área cliente del ventana padre. Hay otra manera de salvar este problema pero no es fácil. Tienes que subclasificar todos los controles de ventana hija en tu ventana padre.

La razón de la existencia de tal inconveniente es que los controles de ventana hija están originalmente diseñados para trabajar dentro de cajas de diálogo, no en una ventana normal. Los colores por defecto de los controles de ventanas hijas, como los botones, es gris porque el área cliente de la caja de diálogo normalmente es gris para que armonicen entre sí sin ninguna intervensión por parte del programador.

Antes de entrar en detalles, deberíamos saber qué es una caja de diálogo. Una caja de diálogo no es más que una ventana normal diseñada para trabajar con controles de ventanas hijas. Windows también proporciona un administrador interno de cajas de diálogo ["dialog box manager"] responsable por gran parte de la lógica del teclado tal como desplazamiento del foco de entrada cuando el ususario presiona Tab, presionar el botón por defecto si la tecla Enter es presionada, etc; así los programadores pueden ocuparse de tareas de más alto nivel. Las cajas de diálogo son usadas primero como dispositivos de entrada/salida. Como tal, una caja de diálogo puede ser considerada como una "caja negra" de entrada/salida lo que siginifica que no tienes que saber cómo funciona internamente una caja de diálogo para usarla, sólo tienes que saber cómo interactuar con ella. Es un principio de la programación orientada a objetos [object oriented programming (OOP)] llamado encapsulación u ocultamiento de la información. Si la caja negra es *perfectamente* diseñada , el usuario puede emplarla sin tener conocimiento de cómo funciona. Lo único es que la caja negra debe ser perfecta, algo difícil de alcanzar en el mundo real. La API de Win32 API también ha sido diseñada como una caja negra.

Bien, parece que nos hemos alejado de nuestro camino. Regresemos a nuestro tema. Las cajas de diálogo han sido diseñadas para reducir la carga de trabajo del programador. Normalmente si tienes que poner controles de ventanas hijas sobre una ventana normal, tienes que subclasificarlas y escribir tú mismo la lógica del teclado. Pero si quieres ponerlas en una caja de diálogo, Windows manejará la lógica por tí. Sólo tienes que saber cómo obtener la entrada del usuario de la caja de diálogo o como enviar órdenes a ella.

Como el menú, una caja de diálogo se define como un recurso. Escribes un plantilla describiendo las características de la caja de diálogo y sus controles y luego compilas el guión de recursos con un compilador de recursos.

Nota que todos los recursos se encuentran en el mismo archivo de guión de recursos. Puedes emplear cualquier editor de texto para escribir un guión de recursos, pero no lo recomiendo. Deberías usar un editor de recursos para hacer la tarea visualmente ya que arreglar la disposición de los controles en la caja de diálgo es una tarea dura de hacer manualmente. Hay disponibles algunos excelentes editores de recursos. Muchos de las grandes suites de compiladores incluyen sus propios editores de recursos. Puedes usar cualquiera para crear un guión de recursos para tu programa y luego cortar las líneas irrelevantes tales como las relacionadas con MFC.

Hay dos tipos principales de cajas de diálogo: modal y no-modal. Una caja de diálogo no-modal te deja cambiar de foco hacia otra ventana. Un ejempo es el diálogo Find de MS Word. Hay dos subtipos de caja de diálogo modal: modal de aplicación y modal de sistema. Una caja de diálogo modal de aplicación no permite cambiar el foco a otra ventana en la misma aplicación sino cambiar el foco de entrada a la ventana de OTRA aplicación. Una caja de diálogo modal de sistema no te permite cambiar de foco hacia otra ventana hasta que respondas a la primera.

Una caja de diálogo no-modal se crea llamando a la función de la API CreateDialogParam. Una caja de diálogo modal se crea llamando a DialogBoxParam. La única diferencia entre una caja de diálogo de no-modal y una modal de sistema es el estilo DS_SYSMODAL. Si quieres incluir el estilo DS_SYSMODAL en una plantilla de caja de diálogo, esa caja de diálogo será modal de sistema.

Puedes comunicarte con cualquier control de ventana hija sobre una caja de diálogo usando la función SendDlgItemMessage. Su sintaxis es:
 

SendDlgItemMessage proto hwndDlg:DWORD,\
                                             idControl:DWORD,\
                                             uMsg:DWORD,\
                                             wParam:DWORD,\
                                             lParam:DWORD

Esta llamada a la API es inmensamene útil para interactuar con un control de ventana hija. Por ejemplo, si quieres obtener el texto de un control de edición, puedes hacer esto:

call SendDlgItemMessage, hDlg, ID_EDITBOX, WM_GETTEXT, 256, ADDR text_buffer

Con el fin de saber qué mensaje enviar, deberías consultar la referencia de la API de Win32.
Windows también provee algunas funciones específicas de la API para controles que permiten obtener y poner datos en los controles rápidamente, por ejemplo, GetDlgItemText, CheckDlgButton etc. Estas funciones específicas para controles son suministradas para conveniencia de los programadores de manera que él no tenga que revisar el significado de wParam y lParam para cada mensaje. Normalmente, deberías usar llamadas a las funciones específicas de la API para controles cada vez que sean disponibles ya que ellas facilitan el mantenimiento del código fuente. Recurre a SendDlgItemMessage sólo si no hay disponible llamadas a funciones específicas de la API.

El manejador de Windows de cajas de diálogos envía varios mensajes a una función " callback" particular llamada procedimiento de caja de diálogo que tiene el siguiente formato:

DlgProc  proto hDlg:DWORD ,\
                        iMsg:DWORD ,\
                        wParam:DWORD ,\
                        lParam:DWORD

El procedimiento de diálogo es similar al procedimiento de ventana excepto por el tipo de valor de retorno, que es TRUE/FALSE en vez de LRESULT. El administrador interno de la caja de diálogo dentro de Windows ES el verdadero procedimiento de ventana para la caja de diálogo. Llama a nuestra caja de diálogo con algunos mensajes que recibió. Así que la regla general es que: si nuestro procedimiento de diálogo procesa un mensaje, DEBE regresar TRUE (1) en eax y si no procesa el mensaje, debe regresar FALSE (0) en eax. Nota que un procedimiento de caja de diálogo no pasa los mensajes no procesados a la llamada DefWindowProc ya que no es realmente un procedimiento de ventana.

Hay dos usos distintos de una caja de diálogo. Puedes usarlas como ventanas principal de tu aplicación o usarla como un dispositivo de entrada. Examinaremos el primer acercamiento en este tutorial. "Usar una caja de diálogo como una ventana principal" puede ser interpretado en dos sentidos.

  1. Puedes usar una plantilla de caja de diálogo como la plantilla de clase que registras al llamar a RegisterClassEx. En este caso, la caja de diálogo se comporta como una ventana "normal": recibe mensajes del procedimiento de ventana referido por el miembro lpfnWndProc de la clase de ventana class, no a través de un procedimiento de caja de diálogo. El beneficio de esto es que no tienes que crear por tí mismo controles de ventana hija, Windows los crea por tí cuando se crea la caja de diálogo. También Windows maneja la lógica del teclado para tí, por ejemplo se encarga de la orden Tab, etc. Además puedes especificar el cursor y el icono de tu ventana en la estructura de la clase de ventana.

  2. Tu programa crea la caja de diálogo sin ninguna ventana padre. Esta aproximación al problema hace inecesario el uso de un bucle de mensajes ya que los mensajes son enviados directamente al procedimiento de ventana de la caja de diálogo. ¡Ya no tienes que registrar la clase de ventana!

Este tutorial va a ser un poco largo. Presentaré la primera aproximación seguida por la segunda.

Ejemplos:


dialog.asm



.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
ClassName db "DLGCLASS",0
MenuName db "MyMenu",0
DlgName db "MyDialog",0
AppName db "Our First Dialog Box",0
TestString db "Wow! I'm in an edit box now",0

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
buffer db 512 dup(?)

.const
IDC_EDIT        equ 3000
IDC_BUTTON      equ 3001
IDC_EXIT        equ 3002
IDM_GETTEXT     equ 32000
IDM_CLEAR       equ 32001
IDM_EXIT        equ 32002

.code
start:
    invoke GetModuleHandle, NULL
    mov    hInstance,eax
    invoke GetCommandLine
    invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
    invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hDlg:HWND
    mov   wc.cbSize,SIZEOF WNDCLASSEX
    mov   wc.style, CS_HREDRAW or CS_VREDRAW
    mov   wc.lpfnWndProc, OFFSET WndProc
    mov   wc.cbClsExtra,NULL
    mov   wc.cbWndExtra,DLGWINDOWEXTRA
    push  hInst
    pop   wc.hInstance
    mov   wc.hbrBackground,COLOR_BTNFACE+1
    mov   wc.lpszMenuName,OFFSET MenuName
    mov   wc.lpszClassName,OFFSET ClassName
    invoke LoadIcon,NULL,IDI_APPLICATION
    mov   wc.hIcon,eax
    mov   wc.hIconSm,eax
    invoke LoadCursor,NULL,IDC_ARROW
    mov   wc.hCursor,eax
    invoke RegisterClassEx, addr wc
    invoke CreateDialogParam,hInstance,ADDR DlgName,NULL,NULL,NULL
    mov   hDlg,eax
    invoke ShowWindow, hDlg,SW_SHOWNORMAL
    invoke UpdateWindow, hDlg
    invoke GetDlgItem,hDlg,IDC_EDIT
    invoke SetFocus,eax
    .WHILE TRUE
        invoke GetMessage, ADDR msg,NULL,0,0
        .BREAK .IF (!eax)
       invoke IsDialogMessage, hDlg, ADDR msg
        .IF eax ==FALSE
            invoke TranslateMessage, ADDR msg
            invoke DispatchMessage, ADDR msg
        .ENDIF
    .ENDW
    mov     eax,msg.wParam
    ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .IF uMsg==WM_DESTROY
        invoke PostQuitMessage,NULL
    .ELSEIF uMsg==WM_COMMAND
        mov eax,wParam
        .IF lParam==0
            .IF ax==IDM_GETTEXT
                invoke GetDlgItemText,hWnd,IDC_EDIT,ADDR buffer,512
                invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
            .ELSEIF ax==IDM_CLEAR
                invoke SetDlgItemText,hWnd,IDC_EDIT,NULL
            .ELSE
                invoke DestroyWindow,hWnd
            .ENDIF
        .ELSE
            mov edx,wParam
            shr edx,16
            .IF dx==BN_CLICKED
                .IF ax==IDC_BUTTON
                    invoke SetDlgItemText,hWnd,IDC_EDIT,ADDR TestString
                .ELSEIF ax==IDC_EXIT
                    invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0
                .ENDIF
            .ENDIF
        .ENDIF
    .ELSE
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .ENDIF
    xor    eax,eax
    ret
WndProc endp
end start


Dialog.rc



#include "resource.h"

#define IDC_EDIT                                       3000
#define IDC_BUTTON                                3001
#define IDC_EXIT                                       3002

#define IDM_GETTEXT                             32000
#define IDM_CLEAR                                  32001
#define IDM_EXIT                                      32003
 

MyDialog DIALOG 10, 10, 205, 60
STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
CAPTION "Our First Dialog Box"
CLASS "DLGCLASS"
BEGIN
    EDITTEXT         IDC_EDIT,   15,17,111,13, ES_AUTOHSCROLL | ES_LEFT
    DEFPUSHBUTTON   "Say Hello", IDC_BUTTON,    141,10,52,13
    PUSHBUTTON      "E&xit", IDC_EXIT,  141,26,52,13, WS_GROUP
END
 

MyMenu  MENU
BEGIN
    POPUP "Test Controls"
    BEGIN
        MENUITEM "Get Text", IDM_GETTEXT
        MENUITEM "Clear Text", IDM_CLEAR
        MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/
        MENUITEM "E&xit", IDM_EXIT
    END
END

Análisis:

Vamos a analizar el primer ejemplo.

Este ejemplo muestra como registrar una plantilla de diálogo como una clase de ventana y crear una "ventana" a partir de esa clase. Simplifica tu programa ya que no tienes que crear tú mismo los controles de ventana hija. Vamos a analizar primero la plantilla de diálogo.

MyDialog DIALOG 10, 10, 205, 60

Declarar el nombre del diálogo, en este caso, "MyDialog" seguido por la palabra clave "DIALOG". Los siguientes cuatro números son: x, y , ancho, y alto de la caja de diálogo en unidades de caja de diálogo no de pixeles [not the same as pixels].

STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK

Declarar los estilos de la caja de diálogo.

CAPTION "Our First Dialog Box"

Este es el texto que aparecerá en la barra de título de la caja de diálogo.

CLASS "DLGCLASS"

Esta línea es crucial. Es esta palabra clave, CLASS, lo que nos permite usar la caja de diálogo como una clase de ventana. Después de la palabra clave está el "nombre de la clase"

BEGIN
    EDITTEXT         IDC_EDIT,   15,17,111,13, ES_AUTOHSCROLL | ES_LEFT
    DEFPUSHBUTTON   "Say Hello", IDC_BUTTON,    141,10,52,13
    PUSHBUTTON      "E&xit", IDC_EXIT,  141,26,52,13
END

El bloque de arriba define los controles de ventana hija en la caja de diálogo. Están definidos entre las palabras claves BEGIN y END. Generalmente la sintaxis es la siguiente:

los tipos de controles son constantes del compilador de recursos así que tienes que consultar el manual.

Ahora vamos a ensamblar el código fuente. La parte interesante es la estructura de la clase de ventana:

Normalmente, este miembro se deja NULL, pero si queremos registrar una plantilla de caja de diálogo como una clase de ventana, debemos poner en este miembro el valor DLGWINDOWEXTRA. Nota que el nombre de la clase debe ser idéntico al que sigue a la palabra clave CLASS en la plantilla de la caja de diálogo. Los miembros restantes se inicializan como es usual. Después de que llenas la estructura de la clase de ventana, la registras con RegisterClassEx. ¿No te resulta esto familiar? Esta es la misma rutina que tienes que hacer con el fin de registrar una clase de ventana normal.

Después de registrar la "clase de ventana", creamos nuestra caja de diálogo. En este ejemplo, lo creo como una caja de diálogo modal con la función CreateDialogParam. Esta función toma 5 parámetros, pero sólo tienes que llenar los primeros dos: el manejador de instancia y el puntero al nombre de la plantila de la caja de diálogo. Nota que el segundo parámetro no es un puntero al nombre de la clase.

En este punto, la caja de diálogo y sus controles de ventana hija son creados por Windows. Tu procedimiento de ventana recibirá el mensaje WM_CREATE como es usual.

Después de que es creada la caja de diálogo, quiero poner el foco de entrada a la caja de edición. Si pongo estas instrucciones en la sección WM_CREATE, la llamada a GetDlgItem fallará ya que en ese momento, ya que en ese instante todavía no se han creado los controles de ventana hija. La única manera de hacer esto es llamarlo después de que la caja de diálogo y todos los controles de ventana hija son creados. Así que pongo estas dos lineas después de la llamada a UpdateWindow. La función GetDlgItem obtiene el ID del control y regresa el manejador del control de ventana asociado. Así es como puedes obtener el manejador de un control de ventana hija si tienes su ID.

       invoke IsDialogMessage, hDlg, ADDR msg
        .IF eax ==FALSE
            invoke TranslateMessage, ADDR msg
            invoke DispatchMessage, ADDR msg
        .ENDIF

El programa introduce el bucle de mensajes y antes de que traduzcamos y despachemos mensajes, llamamos a la función IsDialogMessage para permitir que el administrador [manager] de la caja de diálogo maneje el teclado lógico de nuestra caja de diálogo. Si la función regresa TRUE, significa que el mensaje es enviado a la caja de diálogo y es procesado por el administrador de la caja de diálogo. Nota ahora la diferencia respecto al tutorial previo. Cuando el procedimiento de ventana quiere obtener el texto del control de edición, llama a la fución GetDlgItemText en vez de GetWindowText. GetDlgItemText acepta un ID de control en vez de un manejador de ventana. Eso facilita la llamada en el caso de que utilices una caja de diálogo.



Ahora vamos a la segunda aproximación de cómo usar una caja de diálogo como ventana principal. En el siguiente ejemplo, crearé una aplicación de caja de diálogo modal. ¡No encontrarás un bucle de mensaje ni un procedimiento de ventana porque no son necesarios!


dialog.asm (part 2)



.386
.model flat,stdcall
option casemap:none

DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
DlgName db "MyDialog",0
AppName db "Our Second Dialog Box",0
TestString db "Wow! I'm in an edit box now",0

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
buffer db 512 dup(?)

.const
IDC_EDIT            equ 3000
IDC_BUTTON     equ 3001
IDC_EXIT            equ 3002
IDM_GETTEXT  equ 32000
IDM_CLEAR       equ 32001
IDM_EXIT           equ 32002
 

.code
start:
    invoke GetModuleHandle, NULL
    mov    hInstance,eax
    invoke DialogBoxParam, hInstance, ADDR DlgName,NULL, addr DlgProc, NULL
    invoke ExitProcess,eax

DlgProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .IF uMsg==WM_INITDIALOG
        invoke GetDlgItem, hWnd,IDC_EDIT
        invoke SetFocus,eax
    .ELSEIF uMsg==WM_CLOSE
        invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0
    .ELSEIF uMsg==WM_COMMAND
        mov eax,wParam
        .IF lParam==0
            .IF ax==IDM_GETTEXT
                invoke GetDlgItemText,hWnd,IDC_EDIT,ADDR buffer,512
                invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
            .ELSEIF ax==IDM_CLEAR
                invoke SetDlgItemText,hWnd,IDC_EDIT,NULL
            .ELSEIF ax==IDM_EXIT
                invoke EndDialog, hWnd,NULL
            .ENDIF
        .ELSE
            mov edx,wParam
            shr edx,16
            .if dx==BN_CLICKED
                .IF ax==IDC_BUTTON
                    invoke SetDlgItemText,hWnd,IDC_EDIT,ADDR TestString
                .ELSEIF ax==IDC_EXIT
                    invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0
                .ENDIF
            .ENDIF
        .ENDIF
    .ELSE
        mov eax,FALSE
        ret
    .ENDIF
    mov eax,TRUE
    ret
DlgProc endp
end start


dialog.rc (part 2)



#include "resource.h"

#define IDC_EDIT                                       3000
#define IDC_BUTTON                                3001
#define IDC_EXIT                                       3002

#define IDR_MENU1                                  3003

#define IDM_GETTEXT                              32000
#define IDM_CLEAR                                   32001
#define IDM_EXIT                                       32003
 

MyDialog DIALOG 10, 10, 205, 60
STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
CAPTION "Our Second Dialog Box"
MENU IDR_MENU1
BEGIN
    EDITTEXT         IDC_EDIT,   15,17,111,13, ES_AUTOHSCROLL | ES_LEFT
    DEFPUSHBUTTON   "Say Hello", IDC_BUTTON,    141,10,52,13
    PUSHBUTTON      "E&xit", IDC_EXIT,  141,26,52,13
END
 

IDR_MENU1  MENU
BEGIN
    POPUP "Test Controls"
    BEGIN
        MENUITEM "Get Text", IDM_GETTEXT
        MENUITEM "Clear Text", IDM_CLEAR
        MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/
        MENUITEM "E&xit", IDM_EXIT
    END
END



A continuación el análisis:

    DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD

Declaramos el prototipo de función para DlgProc de manera que podamos referirnos a él con el operador addr en la línea de abajo:

    invoke DialogBoxParam, hInstance, ADDR DlgName,NULL, addr DlgProc, NULL

la línea de arriba llama a la función DialogBoxParam que toma 5 parámetros: el manejador de instancia, el nombre de la plantilla de la caja de diálogo, el manejador de la ventana padre, la dirección del procedimiento de de ventana, y los datos específicos del diálogo. DialogBoxParam crea una caja de diálogo modal. No regresará hasta que la caja de diálogo sea destruida.

    .IF uMsg==WM_INITDIALOG
        invoke GetDlgItem, hWnd,IDC_EDIT
        invoke SetFocus,eax
    .ELSEIF uMsg==WM_CLOSE
        invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0

El procedimiento de la caja de diálogo se observa como un procedimiento de ventana excepto en que no recibe el mensaje WM_CREATE. El primer mensaje que recibe es WM_INITDIALOG. Normalmente puedes poner aquí el código de inicialización. Nota que debes regresar el valor TRUE en eax si procesas el mensaje.

El administrador interno de la caja de diálogo no envía a nuestro procedimiento de diálogo el mensaje WM_DESTROY por defecto cuando WM_CLOSE es enviado a nuestra caja de diálogo. Así que si queremos reaccionar cuando el usuario presiona el botón cerrar [close] en nuestra caja de diálogo, debemos procesar el mensaje WM_CLOSE. En nuestro ejemplo, enviamos el mensaje WM_COMMAND con el valor IDM_EXIT en wParam. Esto tiene el mismo efecto que cuando el usuario selecciona el elemento del menú Exit. EndDialog es llamado en respuesta a IDM_EXIT.

El procesamiento de WM_COMMAND se mantiene igual.

Cuando quieres destruir la caja de diálogo, la única manera es llamar a la función EndDialog. ¡No emplees DestroyWindow! EndDialog no destruye la caja de diálogo de inmediato. Sólo pone una bandera para ser revisada por el administrador interno de la caja de diálogo y continúa para ejecutar la siguiente instrucción.

Ahora vamos a revisar el archivo de recursos. El cambio notable es que en vez de usar una cadena de texto como nombre de menú usamos un valor, IDR_MENU1. Esto es necesario si quieres agregar un menú a la caja de diálog creada con DialogBoxParam. Nota que en la plantilla de caja de diálogo tienes que agregar la palabra clave MENU seguida por el ID del recurso.

Una diferencia que puedes observar entre los dos ejemplos de este tutorial es la carencia de un icono en el último ejemplo. Sin embargo, puedes poner el icono enviando el mensaje WM_SETICON a la caja de diálgo durante WM_INITDIALOG.


Índice

Siguiente

[Iczelion's Win32 Assembly Homepage]

n u M I T_o r's   Programming Page

Este tutorial, original de Iczelion, ha sido traducido por:   n u M I T_o r

www.000webhost.com