El código que está tratando se basa en los títulos de los botones individuales para identificarlos. Por ejemplo, se utiliza el código siguiente para obtener un identificador para el botón "1":
hwndChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "Button", "1");
que especifica "botón" para el nombre de la clase de ventana, y "1" para el nombre de la ventana (en el caso de un botón, esto es lo mismo que el texto de título que se muestra en el botón).
Este código funcionó bien en Windows XP (y versiones anteriores), donde los botones de la calculadora se identificaron con leyendas textuales. El botón "1" tenía un nombre de ventana de "1" y, por lo tanto, "1" se mostraba como el título del botón.
Sin embargo, parece que las cosas han cambiado en Windows 7 (posiblemente también en Vista, aunque no puedo verificar esto porque no tengo acceso a dicho sistema). El uso de Spy ++ para investigar la ventana de la calculadora confirma que el botón "1" ya no tiene un nombre de ventana de "1". De hecho, no tiene un nombre de ventana en absoluto; la leyenda es NULL Presumiblemente, el nuevo aspecto elegante de la calculadora requería que los botones se dibujaran a medida, por lo que los subtítulos ya no son necesarios para indicar qué botón corresponde a cada función. Las rutinas de pintura personalizadas se encargan de dibujar los subtítulos necesarios.
Como no se puede encontrar ningún botón con el texto de ventana que especificó, se devuelve un valor de 0 (NULL
) para el identificador de ventana.
El documentation for the FindWindowEx
function indica que puede especificar NULL
para el parámetro lpszWindow
, pero que esta voluntad, por supuesto, partido todas las ventanas de la clase especificada. Probablemente no es lo que quiere en este caso, ya que la aplicación de calculadora tiene un montón de botones.
No conozco una buena solución. La calculadora no fue diseñada para ser "automatizada" de esta manera, y Microsoft nunca garantizó que no cambiaría su funcionamiento interno. Ese es un riesgo que toma al usar este enfoque para meterse con las ventanas de otras aplicaciones.
EDIT: El código de haber asociado también está mal de otra manera bastante grave, incluso en las versiones anteriores de Windows. Declara la variable hwnd
como tipo int
, en lugar de como tipo IntPtr
. Dado que un identificador de ventana es un puntero, siempre debe almacenarlo como un tipo IntPtr
. Eso también soluciona el lanzamiento feo en la llamada a la función FindWindowEx
que debería haber enviado banderas rojas.
También deberá corregir la declaración de SendMessage
para que su primer parámetro sea del tipo IntPtr
.
El código debería haberse escrito así:
IntPtr hwnd = IntPtr.Zero;
IntPtr hwndChild = IntPtr.Zero;
//Get a handle for the Calculator Application main window
hwnd = FindWindow(null, "Calculator");
if(hwnd == IntPtr.Zero)
{
if(MessageBox.Show("Couldn't find the calculator" +
" application. Do you want to start it?",
"TestWinAPI",
MessageBoxButtons.YesNo) == DialogResult.Yes)
{
System.Diagnostics.Process.Start("Calc");
}
}
else
{
//Get a handle for the "1" button
hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Button", "1");
//send BN_CLICKED message
SendMessage(hwndChild, BN_CLICKED, 0, IntPtr.Zero);
//Get a handle for the "+" button
hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Button", "+");
//send BN_CLICKED message
SendMessage(hwndChild, BN_CLICKED, 0, IntPtr.Zero);
//Get a handle for the "2" button
hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Button", "2");
//send BN_CLICKED message
SendMessage(hwndChild, BN_CLICKED, 0, IntPtr.Zero);
//Get a handle for the "=" button
hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Button", "=");
//send BN_CLICKED message
SendMessage(hwndChild, BN_CLICKED, 0, IntPtr.Zero);
}
¿Qué versión de Windows está ejecutando? –
Si tiene un problema con P/Invoke, publique su declaración con el atributo 'DllImport'. Si tiene algún problema con algún código, publique el código que no está funcionando. – Gabe
@CodyGray Tengo Windows 7 Professional. – teenup