Leer contraseñas

A veces no nos interesa que el texto que se introduce en un control edit no se muestre en pantalla de forma que pueda ser reconocido. El caso más frecuente es cuando se introducen contraseñas. En esos casos se hace que el texto introducido se sustituya por otros caracteres. El usuario que introduce la contraseña sabe qué escribe, porque es el que maneja el teclado, pero una persona que observe este proceso no podrá reconocer el texto en pantalla, y le resultará complicado deducir el texto mirando el teclado.

Para que un control edit se comporte de este modo bastará con activar el estilo ES_PASSWORD al crear el control.

Las funciones para asignar valores iniciales o recuperarlos del control funcionanrán igual que con los controles normales, el estilo sólo afecta al modo en que se visualiza el texto, no a su contenido.

Por defecto, el carácter que se usa para sustituir los introducidos es el asterisco, pero esto se puede modificar usando el mensaje EM_SETPASSWORDCHAR. Si se utiliza un carácter nulo se mostrará el texto que introduzca el usuario.

También podemos usar el mensaje EM_GETPASSWORDCHAR para averiguar el carácter que se usa actualmente para sustituir lo introducidos por el usuario.

Estos mensajes sólo están disponibles para controles edit de una línea.

Crearemos otro programa de ejemplo basado en el ejemplo 5. En este caso añadiremos tres RadioButtons con tres opciones distintas de caracteres: el '*', el '·' y el nulo.

El primer paso es modificar el fichero de recursos para añadir los tres botones:

DialogoPrueba DIALOG 0, 0, 118, 98
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
CAPTION "Diálogo de prueba"
FONT 8, "Helv"
BEGIN
 CONTROL "Grupo 1", ID_GRUPO1, "BUTTON",
    BS_GROUPBOX | WS_CHILD | WS_VISIBLE | WS_GROUP,
    4, 5, 76, 52
 CONTROL "Asteriscos", ID_RADIOBUTTON1, "BUTTON",
    BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP,
    11, 15, 60, 12
 CONTROL "Puntos", ID_RADIOBUTTON2, "BUTTON",
    BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP,
    11, 28, 60, 12
 CONTROL "Visible", ID_RADIOBUTTON3, "BUTTON",
    BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP,
    11, 41, 60, 12
 CONTROL "Texto:", -1, "STATIC", 
    SS_LEFT | WS_CHILD | WS_VISIBLE, 
    8, 64, 28, 8
 CONTROL "", ID_TEXTO, "EDIT", 
    ES_LEFT | ES_PASSWORD | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP,
    36, 64, 76, 12
 CONTROL "Aceptar", IDOK, "BUTTON", 
    BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
    8, 80, 45, 14
 CONTROL "Cancelar", IDCANCEL, "BUTTON", 
    BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
    61, 80, 45, 14
END

También añadiremos las constantes necesarias en el fichero win051.h:

#define ID_GRUPO1 101
#define ID_RADIOBUTTON1 102
#define ID_RADIOBUTTON2 103
#define ID_RADIOBUTTON3 104

Tendremos que modificar la estructura de datos para pasar al procedimiento de diálogo:

typedef struct stDatos {
   char Texto[80];
   int Estado;
} DATOS;

En el procedimiento de ventana principal iniciaremos los datos miembro:

LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HINSTANCE hInstance;
    /* Variables para diálogo */
    static DATOS Datos;

    switch (msg)                  /* manipulador del mensaje */
    {
        case WM_CREATE:
           hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
           /* Inicialización de los datos de la aplicación */
           strcpy(Datos.Texto, "Inicial");
           Datos.Estado = 0;
           return 0;
           break;
...

Por último, procesaremos los mensajes procedentes de los RadioButtons e iniciaremos los controles en el procedimiento de diálogo:

BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static DATOS *Datos;
    char opcion[3] = "*·\000";

    switch (msg)                  /* manipulador del mensaje */
    {
        case WM_INITDIALOG:
           SendDlgItemMessage(hDlg, ID_TEXTO, EM_LIMITTEXT, 80, 0L);
           Datos = (DATOS *)lParam;
           SetDlgItemText(hDlg, ID_TEXTO, Datos->Texto);
           /* Aplicar el carácter según el valor de estado */
           SendMessage(GetDlgItem(hDlg, ID_TEXTO), EM_SETPASSWORDCHAR, opcion[Datos->Estado], 0);
           /* Activar el radiobutton */
           CheckRadioButton(hDlg, ID_RADIOBUTTON1, ID_RADIOBUTTON3,
              ID_RADIOBUTTON1+Datos->Estado);
           SetFocus(GetDlgItem(hDlg, ID_TEXTO));
           return FALSE;  
        case WM_COMMAND:
           switch(LOWORD(wParam)) {
              case ID_RADIOBUTTON1:
              case ID_RADIOBUTTON2:
              case ID_RADIOBUTTON3:
                 Datos->Estado = LOWORD(wParam)-ID_RADIOBUTTON1;
                 SendMessage(GetDlgItem(hDlg, ID_TEXTO), EM_SETPASSWORDCHAR, opcion[Datos->Estado], 0);
                 SetFocus(GetDlgItem(hDlg, ID_TEXTO));
                 break;
...

A pesar de que la documentación del API afirma que el control edit se actualiza tan pronto recibe un mensaje EM_SETPASSWORDCHAR, lo cierto es que no parece que sea así, de modo que en este ejemplo hemos optado por asignar el foco al control edit, esto obliga a que se actualice su aspecto.

Ejemplo 51


  Nombre Fichero Fecha Tamaño Contador Descarga
D Ejemplo 51 win051.zip 2005-11-07 3426 bytes 129