API de Windows (4º)

Algunas funciones interesantes del API de Windows

Actualizado el 15/Ago/2007
Pulsa aquí para ver todos los links del API
Declaraciones de funciones del API y ejemplos para VB6 y .NET


Funciones y ejemplos:

  1. Cómo usar los objetos del Shell Windows (ShellObjects) (07/Sep/01)
  2. Cambiar el texto de los botones de un MsgBox (14/Sep/01)
  3. Saber el directorio de Windows y el System (15/Oct/01)
     
  4. Especial Resolución de Pantalla: (04/Nov/01)
    Averiguar la resolución actual y número de colores, usando API.
    Cambiar/restaurar la resolución de forma rápida.
    Enumerar las resoluciones disponibles y cambiar/restaurar la resolución de la pantalla.
     
  5. Convertir un Path de nombre largo a nombre corto (06/Nov/01)
  6. Convertir un Path de nombre corto a nombre largo (06/Nov/01)
  7. Recorrer un TextBox multiline línea a línea (09/Nov/01)
  8. ShellObjects (tareas del Shell de Windows) (18/Nov/01)
  9. Temas de Windows XP: consejos para usarlos desde Visual Basic clásico (30/Oct/02)
  10. Copiar, cortar, pegar, deshacer... usando el API de Windows (28/Dic/02)
  11. Deshabilitar Alt+Tab y otras teclas en Windows NT/2000/XP (09/Mar/03)
  12. Revisión del código para leer ficheros INI desde Visual Basic (14/Sep/03)
  13. Especial Docking:
    Poner un formulario dentro de un control picture (25/Ene/04)
    Cambiar el tamaño de dos controles (split) (25/Ene/04)
    Meter el bloc de notas (u otra aplicación) dentro de un picture (25/Ene/04, rev. 26/May/04)
     
  14. Poner nuestra aplicación en el inicio de Windows (registro) (14/May/04)
  15. Equivalencias del API de Windows con .NET (28/Feb/05)
  16. Cerrar aplicaciones (clase cWindows) (02/Ene/99 - 12/Ago/05)
  17. Averiguar la versión de Windows usando API (24/May/07)
  18. Ejecutar un acceso directo desde VB6 con ShellExecute (15/Ago/07)
  19. Averiguar la posición del cursor con GetCursorPos (08/Jul/08)

 

  1. Cambiar el texto de los botones de un MsgBox (14/Sep/2001)

Con el ejemplo que te muestro a continuación, podrás cambiar el texto que se muestra en los botones de un cuadro de diálogo, en este caso de un MsgBox.
En este ejemplo, se cambia el texto YES/SI por "Alta" y el NO por "Modificación", que era lo que quería hacer el que hizo la consulta: *****
(he omitido el nombre de quién tenía la duda, por petición, (aunque no directa a mi persona), del mismo).
Este código es una "adaptación" de un ejemplo en C que envió ????? (¿puedo decir el nombre?) al grupo de noticias de VB.

Este es el código en C:


LRESULT CALLBACK CallWndRetProc(
    int nCode, WPARAM wParam, LPARAM lParam)
{
LRESULT lr = CallNextHookEx(hook, nCode, wParam, lParam);
if (nCode < 0) return lr;

CWPRETSTRUCT s = *((CWPRETSTRUCT *)lParam);
if (s.message == WM_INITDIALOG)
{
SetDlgItemText(s.hwnd, IDYES, "Alta");
SetDlgItemText(s.hwnd, IDNO, "Modificación");
}
return lr;
}

...

HHOOK hook = SetWindowsHookEx(
            WH_CALLWNDPROCRET,
            CallWndRetProc,
            NULL,
            GetCurrentThreadId());

if (hook)
{
    MessageBox(hwnd, "Texto del mensaje", "Título", MB_YESNO);
UnhookWindowsHookEx(hook);
}


Para crear el proyecto, añade un formulario, inserta un botón y una etiqueta. Inserta este código en el formulario:


'------------------------------------------------------------------------------
' Subclasificar un MsgBox para cambiar el texto de los botones      (13/Sep/01)
'
' Versión en Visual Basic de un ejemplo en C enviado a las news por:
' "Hernán"  el 13/Sep/2001
'
' ©Guillermo 'guille' Som, 2001
'------------------------------------------------------------------------------
Option Explicit

Private Sub Command1_Click()
    Dim hInst As Long
    Dim Thread As Long
    Dim i As Long

    ' Crear el hook para subclasificar el MsgBox
    hInst = GetWindowLong(Me.hWnd, GWL_HINSTANCE)
    Thread = GetCurrentThreadId()
    hHook = SetWindowsHookEx(WH_CALLWNDPROCRET, AddressOf CallWndRetProc, hInst, Thread)

    ' Mostrar el MsgBox
    i = MsgBox("Pulsa en Alta o Modificación.", vbYesNo)
    ' Alta será vbYes, Modificación será vbNo
    If i = vbYes Then
        Label1 = "Has pulsado en Alta"
    ElseIf i = vbNo Then
        Label1 = "Has pulsado en Modificación"
    End If
End Sub


Añade también un módulo BAS y añade el siguiente código:


'------------------------------------------------------------------------------
' MSubclassMsgBox                                                   (14/Sep/01)
' Módulo para subclasificar un MsgBox y cambiar el texto de los botones
'
' Versión en Visual Basic de un ejemplo en C enviado a las news por:
' "Hernán"  el 13/Sep/2001
'
' ©Guillermo 'guille' Som, 2001
'------------------------------------------------------------------------------
Option Explicit
'
Public hHook As Long
Public Const WH_CALLWNDPROCRET = 12
Public Const GWL_HINSTANCE = (-6)

Private Type tagCWPRETSTRUCT
    lResult As Long
    lParam As Long
    wParam As Long
    message As Long
    hWnd As Long
End Type

Private Const WM_INITDIALOG = &H110

Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
    (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Public Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Public Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" _
    (ByVal idHook As Long, ByVal lpfn As Long, _
    ByVal hmod As Long, ByVal dwThreadId As Long) As Long

Private Declare Function UnhookWindowsHookEx Lib "user32" _
    (ByVal hHook As Long) As Long
Private Declare Function CallNextHookEx Lib "user32" _
    (ByVal hHook As Long, ByVal nCode As Long, _
    ByVal wParam As Long, lParam As Any) As Long

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
    (Destination As Any, Source As Any, ByVal Length As Long)

' Dialog Box Command IDs
Private Const IDOK = 1
Private Const IDCANCEL = 2
Private Const IDABORT = 3
Private Const IDRETRY = 4
Private Const IDIGNORE = 5
Private Const IDYES = 6
Private Const IDNO = 7

Private Declare Function SetDlgItemText Lib "user32" Alias "SetDlgItemTextA" _
    (ByVal hDlg As Long, ByVal nIDDlgItem As Long, _
    ByVal lpString As String) As Long

Public Function CallWndRetProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Dim lr As Long
    Dim s As tagCWPRETSTRUCT
    '
    lr = CallNextHookEx(hHook, nCode, wParam, lParam)
    If (nCode < 0) Then
        CallWndRetProc = lr
        Exit Function
    End If
    '
    ' Convertir lParam en una estructura
    Call CopyMemory(s, ByVal lParam, Len(s))
    '
    If (s.message = WM_INITDIALOG) Then
        ' Modificar el texto de los botones
        Call SetDlgItemText(s.hWnd, IDYES, "Alta")
        Call SetDlgItemText(s.hWnd, IDNO, "Modificación")
        ' Release the CBT hook
        UnhookWindowsHookEx hHook
        lr = 0&
    End If

    CallWndRetProc = lr
End Function

Ejecútalo con F5 y pulsa en el botón, te mostrará un cuadro de diálogo como este que te muestro:

Y ya está.

Precauciones:
No interrumpas el programa mientras se muestra el cuadro de diálogo, (aunque en teoría no debería pasar nada si lo hicieras), pero sobre todo "procura" que el Visual Basic no se pare dentro de la función CallWndRetProc, ya que se colgaría dando error de protección o algo por el estilo.
Tampoco añadas ningún Debug.Print ni nada que pudiera hacer que se detenga el VB.
Una vez compilado estas precauciones no son aplicables.

Gracias Hernán por ese código en C.


  2. Saber el directorio de Windows y el System (15/Oct/2001)

Esto ya lo sabrás o lo has podido ver en otras páginas, incluso lo de averiguar el directorio Windows ya tiene un link en la página de API, pero no para el System, así que, como los dos están bastante relacionados, los pongo juntos, ejemplo incluido, por supuesto.
Es que me hizo falta y tuve que rebuscar un poco para encontrarlo... 8-)

Para saber cual es el directorio de Windows, usaremos esta función del API: GetWindowsDirectory y para el directorio System, esta otra: GetSystemDirectory.
La forma de usarlas es prácticamente igual, pero aún así temuestro un ejemplo para cada una de ellas.
Primero las declaraciones de estas dos funciones del API y después el código de ejemplo.


' Funciones del API:
Private Declare Function GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" _
    (ByVal lpBuffer As String, ByVal nSize As Long) As Long

Private Declare Function GetSystemDirectory Lib "kernel32" Alias "GetSystemDirectoryA" _
    (ByVal lpBuffer As String, ByVal nSize As Long) As Long

    Dim buf As String
    Dim ret As Long
    '
    ' Obtener el directorio de windows
    buf = String$(260, Chr$(0))
    ret = GetWindowsDirectory(buf, Len(buf))
    Text1.Text = Left$(buf, ret)
    '
    ' Obtener el directorio de System
    buf = String$(260, Chr$(0))
    ret = GetSystemDirectory(buf, Len(buf))
    Text2.Text = Left$(buf, ret)

  4. Convertir un Path de nombre largo a nombre corto (06/Nov/2001)

Pues eso... hay veces que necesitamos esta conversión, aunque menos que la contraria... de nombre corto a nombre largo, la cual te muestro en el siguiente punto: ¡usando API! ya que antes la usaba haciendo malabarismos para poder sacar el nombre largo... pero eso te lo explico en el mencionado siguiente punto.

Esta es la declaración del API para 32 bits y un ejemplo de cómo usarla.


Private Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" _
    (ByVal lpszLongPath As String, ByVal lpszShortPath As String, _
    ByVal cchBuffer As Long) As Long

    Dim sBuf As String * 260
    Dim i As Long
    i = GetShortPathName(Text1, sBuf, Len(sBuf))
    Text2 = Left$(sBuf, i)

Esto ya lo sabrás o lo has podido ver en otras páginas, incluso lo de averiguar el directorio Windows ya tiene un link en la página de API,


  5. Convertir un Path de nombre corto a nombre largo (06/Nov/2001)

Esta conversión es más utilizada, sobre todo si nuestra aplicación recibe parámetros de ficheros, tal es el caso en el que se suelte un fichero sobre el icono de la aplicación, en esos casos, el Windows suele "soltar" el nombre corto del fichero y la verdad es que lo justo sería saber el nombre largo.
Esta conversión antes la hacía mediante código, código que saqué de algún artículo de la Knowledge Base, pero el otro día, mirando en los ficheros de cabecera de Windows, me topé con la declaración en C de dicha función, así que la convertí para usarla en Visual Basic.
Y esta es la forma de declarar dicha función, (también acompaño un ejemplo de cómo usarla).


Private Declare Function GetLongPathName Lib "kernel32" Alias "GetLongPathNameA" _
    (ByVal lpszShortPath As String, ByVal lpszLongPath As String, _
    ByVal cchBuffer As Long) As Long

    Dim sBuf As String * 260
    Dim i As Long
    i = GetLongPathName(Text2, sBuf, Len(sBuf))
    Text1 = Left$(sBuf, i)

  6. Recorrer un TextBox multiline línea a línea (09/Nov/2001)

Esto ya estaba puesto en la entrega 32 del Curso Básico, pero lo pongo por separado para que lo puedas encontrar más rápido.
La declaración tendrás que ponerla en la parte general del formulario y para usar el procedimiento, tendrás que pasar en el parámetro el textbox multiline que quieras imprimir.
Por supuesto, si no lo quieres imprimir, puedes usarlo para leer línea a línea.


' Función del API de Windows de 32 bits de múltiple uso
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
    (ByVal hWnd As Long, ByVal wMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long


Private Sub ImprimirPorLinea(qControl As TextBox)
    ' Este procedimiento tomará cada línea de un textbox multiline  (23/Ene/00)
    ' y lo imprimirá en la impresora predeterminada
    '
    ' El parámetro qControl, será el TextBox a usar, en este caso no es necesario
    ' ya que sólo tenemos un TextBox, pero si se usaran varios...
    ' sería un procedimiento de uso genérico...
    '
    Dim i As Long, k As Long
    Dim L1 As Long, L2 As Long
    ' Constantes para usar con SendMessage
    Const EM_GETLINECOUNT = &HBA
    Const EM_LINEFROMCHAR = &HC9
    Const EM_LINELENGTH = &HC1
    Const EM_LINEINDEX = &HBB   '--- Faltaba esta declaración       (21/Abr/00)

    ' Número de líneas del TextBox
    k = SendMessage(qControl.hWnd, EM_GETLINECOUNT, 0, 0&)

    Printer.Print ""
    For i = 0 To k - 1
        ' Primer carácter de la línea actual
        L1 = SendMessage(qControl.hWnd, EM_LINEINDEX, i, 0&) + 1
        ' Longitud de la línea actual
        L2 = SendMessage(qControl.hWnd, EM_LINELENGTH, L1, 0&)
        ' Imprimimos el trozo de texto que representa a una línea
        Printer.Print Mid$(qControl.Text, L1, L2)
    Next
    ' Le indicamos que ya no hay más que imprimir
    Printer.EndDoc
End Sub

 


Volver a la página del API

ir al índice