2010-02-21 21 views
5

Me preguntaba si alguien podría darnos una idea de cómo implementar el selector de ventana en Winspector Spy. Básicamente, me gustaría proporcionar un panel sobre el que pueda presionar el mouse, arrastrarlo a otra ventana de procesos (o subventana) y sacar algo como HWND. Idealmente, haría esto en C#, pero si solo es posible al ajustar las API de C, entonces puedo hacerlo en C++.Arrastrar y soltar como Winspector Spy

Me metí con el evento DragDrop y llamé a DoDragDrop con el mouse hacia abajo en C#, pero no estaba realmente seguro de que eso pudiera darme lo que quería. ¿Será más fácil obtener la posición X/Y global del mouse y encontrar la ventana más alta en esa ubicación? ¿Hay una API que hace eso automáticamente para mí dados los parámetros x, y?

EDIT: acaba de descubrir WindowFromPoint para la última pregunta

Respuesta

5

Normalmente no recibe los mensajes del mouse cuando el mouse no está sobre su ventana. Pero es necesario para hacer operaciones de arrastrar y soltar. Entonces, Windows proporciona un mecanismo llamado captura de mouse. Para evitar que se abuse de la captura de mouse, solo puede capturar el mouse en un mensaje de botón. Una vez que tiene la captura, obtiene mensajes de mover el mouse sin importar dónde esté el mouse en la pantalla hasta que suelte la captura o cuando Windows vea el mensaje de botón correspondiente.

El código C++ para esto parece algo como esto

case WM_LBUTTONDOWN: 
    { 
    SetCapture(hwnd); 
    } 
    break; 

case WM_MOUSEMOVE: 
    if (GetCapture() == hwnd) 
     { 
     POINT pt = {GET_MOUSE_X(lParam), GET_MOUSE_Y(lParam)); 
     ClientToScreen(hwnd, &pt); 
     HWND hwndAtPoint = WindowFromPoint(pt); 
     // Show info for hwndAtPoint.... 
     } 
    break; 

    case WM_LBUTTONUP: 
    if (GetCapture() == hwnd) 
     { 
     ReleaseCapture(); 
     } 
    break; 

    case WM_CANCELMODE: 
    // this is a request from Windows that leave my modal state 
    if (GetCapture() == hwnd) 
     ReleaseCapture(hwnd); 
    break; 

    case WM_CAPTURECHANGED: 
    // notification that I lost capture (I released it or it was taken from me) 
    break;  

La función GetAncestor puede ser útil para pasar de la ventana en el punto, a la ventana de nivel superior que posee. GetWindow se puede utilizar para caminar por el árbol de la ventana.

En .NET, la clase de control tiene una propiedad de captura que hace lo mismo que ver http://msdn.microsoft.com/en-us/library/system.windows.forms.control.capture.aspx

+0

Esto fue genial, muchas gracias. –

0

Importaciones: usando System.Runtime.InteropServices;

Mi sugerencia, cuando el mouse está en su formulario, maneje los eventos mouse mover/mouse arriba (Para capturar el mouse fuera de su formulario usando un gancho de Windows, vea aquí: http://support.microsoft.com/kb/318804), y cuando se suelta el botón del mouse , obtener la posición del ratón en la pantalla, y obtener la ventana tras el cursor, utilizando el enlace que ya ha proporcionado la siguiente manera:

[DllImport("user32.dll")] 
public static extern IntPtr WindowFromPoint(Point lpPoint); 
[DllImport("user32.dll")] 
public static extern bool GetCursorPos(out Point lpPoint); 
public static IntPtr GetWindowUnderCursor() 
{ 
    Point ptCursor = new Point(); 
    if (!(PInvoke.GetCursorPos(out ptCursor))) 
     return IntPtr.Zero; 
    return WindowFromPoint(ptCursor); 
} 

Ahora usted tiene su identificador de ventana, a partir de ahí las posibilidades son infinitas.

NOTA: El enlace de arriba, (el gancho ventanas) sólo funcionará si el ratón se produce hacia abajo en su forma, y ​​el gancho termina cuando el ratón se levanta

0

simple. Simplemente establece la captura del mouse con el mouse hacia abajo, para que pueda obtener todos los mensajes del mouse, incluso si están fuera de su propia ventana. Luego, con el mouse hacia arriba, usa WindowFromPoint.

No estoy familiarizado con .NET, pero con la API Win32, usa SetCapture para establecer la captura del mouse.

0

usted podría mirar a la fuente de C++ para Winspy++, otro programa de ventana de inspección similar a Winspector espía. Sin embargo, no conozco ningún programa de código abierto de C# como este.

2

Tendrá que considerar primero cómo dibujar el rectángulo alrededor de la ventana, que afecta al resto de su código. La forma más sencilla de hacerlo es mediante el uso de un formulario que tenga su TransparencyKey configurado en BackColor y FormBorderStyle establecido en None.Dibuje un rectángulo en el evento Paint, del mismo tamaño que el ClientRectangle del formulario, que le proporciona un rectángulo visible con todo lo demás transparente. Establezca la propiedad Ubicación y Tamaño del formulario para que coincida con la ventana que encontró.

Ahora encontrando la ventana desde la posición del mouse. No puede usar WindowFromPoint(), no considera las ventanas deshabilitadas. Tendrá que usar EnumWindows(). En la devolución de llamada, llame a GetWindowRect() y compruebe si el mouse se encuentra dentro del rectángulo. Asegúrese de ignorar su ventana de dibujo rectangular.

Cuando obtiene una coincidencia, ahora llame a GetWindow() repetidamente con el GW_HWNDPREV para encontrar las ventanas que se superponen a la ventana que encontró. Sigue revisando el rectángulo y sigue ignorando la ventana de tu rectángulo.

Esto finalmente le proporciona la ventana de nivel superior en la que se encuentra el cursor del mouse. Ahora use ChildWindowFromPoint() para verificar si el mouse está en una ventana secundaria, si hay alguna. Crea tu forma de dibujo rectangular, si es necesario, y dale el mismo tamaño y ubicación que la ventana encontrada.

Llame este código del evento MouseMove de, por ejemplo, un PictureBox que muestra un gráfico de diana. Establezca su propiedad Capture en verdadero en su evento MouseDown.

Cierre el método Close() de su formulario de dibujo rectangular en el evento MouseUp.

1

Puesto que usted ha etiquetado esto con C#, puedo poner en un enlace o dos para este trabajo que usted está tratando de lograr y se espera que le dará el necesario conocimiento de cómo lograr esto:

Todos los artículos anteriores están en CodeProject.

Espero que esto ayude, Saludos cordiales, Tom.