2012-02-17 14 views
5

Nella mia applicazione C# .NET 4, utilizzo WndProc per elaborare alcuni messaggi che riguardano principalmente il ridimensionamento dell'applicazione a/da schermo intero.Gestione del messaggio AeroSnap in WndProc

In questo momento sto solo occupa delle SC_MAXIMIZE e WM_NCLBUTTONDBLCLK per determinare se la finestra viene ridimensionata da o verso uno stato ingrandito (lo so non ho bisogno WndProc per gestire SC_MAXIMIZE, ma Form_Resize non sembrava al fuoco per un WM_NCLBUTTONDBLCLK messaggio quando faccio doppio clic sulla barra del titolo dell'applicazione

Ora ho notato che se I Aero scatta la finestra nella parte superiore dello schermo per ingrandirla, nessuno dei messaggi precedenti viene pubblicato in modo che non venga applicata una determinata logica quando la finestra è ingrandita tramite Aero Snap. Voglio solo gestire il messaggio se la finestra è scattata nella parte superiore dello schermo anziché a destra o a sinistra, o se una finestra non è aperta da quella ingrandita osizione.

Non sono riuscito a trovare nessuno dei messaggi finestra relativi a Aero Snap. Qualcuno sa di riferimenti per quei messaggi?

+0

Mi sono chiesto anche questo ... Non sono mai stato in grado di capirlo, comunque. – aboveyou00

risposta

7

Suppongo che non ci siano messaggi speciali qui; Aero probabilmente utilizza solo le semplici API Win32 - ShowWindow(SW_MAXIMIZE) e simili.

La cosa da uderstand con i messaggi SC_ sono che quelli sono richieste da un menu chiedendo la finestra per ridimensionare/restore/etc in sé, ma che non è l'unico meccanismo per cambiare le dimensioni della finestra. Quello che probabilmente sta succedendo è che quando una finestra diventa SC_MAXIMIZE, DefWndProc implementa ciò chiamando ShowWindow (SW_MAXIMIZE).

Il tuo miglior risultato è ascoltare il messaggio WM_SIZE, che riceve la finestra, indipendentemente da cosa ha attivato la modifica della dimensione: menu di sistema, API o altri mezzi. In particolare, lParam ti consente di sapere se la finestra è stata ingrandita (SIZE_MAXIMIZED) o ripristinata (SIZE_RESTORED).

+3

Questo è corretto. Non ci sono notifiche speciali inviate come risultato di Aero Snap. Usa i messaggi standard 'WM_MOVING' /' WM_MOVE' e 'WM_SIZING' /' WM_SIZE'. Se li elabora senza chiamare 'DefWindowProc', Aero Snap non funzionerà per la tua finestra. Sì, potresti ascoltare 'WM_SIZE', ma probabilmente stai meglio in generale usando [' WM_WINDOWPOSCHANGED'] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms632652.aspx) . È una funzione "nuova", introdotta in err, Windows 3.1. :-) [Lettura pertinente] (http://blogs.msdn.com/b/oldnewthing/archive/2008/01/15/7113860.aspx). –

+1

Il fermo con POSCHANGED è ottenuto per * qualsiasi * spostamento/cambio di dimensione, anche quando la finestra viene spostata prima dello "snap", quindi è necessario fare più filtraggio. E non so se è possibile determinare uno "snap" massimale dai suoi parametri - non c'è un indicatore ovvio che la finestra sia stata massimizzata. Con WM_SIZE, controlla lParam e il gioco è fatto! – BrendanMcK

+0

Sì, è necessario fare un po 'di filtraggio. Questo è fondamentalmente inevitabile, dovrai filtrare 'WM_SIZE' per assicurarti di trattare solo gli eventi di ridimensionamento avviati da Aero Snap. Il punto è che tutto il tuo codice di gestione è in un posto. Non vedo davvero la differenza tra un'istruzione 'switch' all'interno del tuo gestore di messaggi' WM_WINDOWPOSCHANGED' e un'istruzione 'switch' all'interno della tua finestra che gestisce' WM_MOVE', 'WM_SIZE', ecc.Suppongo che con un grande potere derivino grandi responsabilità; o uno funzionerà. –

2

Questo è il codice per la gestione del messaggio WM_WINDOWPOSCHANGING per Maximize invece del messaggio WM_SIZE. Grazie alle 20 o più domande su SO che ho dovuto leggere per trovare tutti i bit per metterlo insieme e farlo funzionare. Questo risolve i problemi che stavo avendo con più monitor usando risoluzioni diverse.

//register the hook 
public static void WindowInitialized(Window window) 
{ 
    IntPtr handle = (new WindowInteropHelper(window)).Handle; 
    var hwndSource = HwndSource.FromHwnd(handle); 
    if (hwndSource != null) 
    { 
     hwndSource.AddHook(WindowProc); 
    } 
} 

//the important bit 
private static IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 
{ 
    switch (msg) 
    { 
     case 0x0046: //WINDOWPOSCHANGING 
      var winPos = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS)); 
      var monitorInfo = new MONITORINFO(); 
      IntPtr monitorContainingApplication = MonitorFromWindow(hwnd, MonitorDefaultToNearest); 
      GetMonitorInfo(monitorContainingApplication, monitorInfo); 
      RECT rcWorkArea = monitorInfo.rcWork; 
      //check for a framechange - but ignore initial draw. x,y is top left of current monitor so must be a maximise 
      if (((winPos.flags & SWP_FRAMECHANGED) == SWP_FRAMECHANGED) && (winPos.flags & SWP_NOSIZE) != SWP_NOSIZE && winPos.x == rcWorkArea.left && winPos.y == rcWorkArea.top) 
      { 
       //set max size to the size of the *current* monitor 
       var width = Math.Abs(rcWorkArea.right - rcWorkArea.left); 
       var height = Math.Abs(rcWorkArea.bottom - rcWorkArea.top); 
       winPos.cx = width; 
       winPos.cy = height; 
       Marshal.StructureToPtr(winPos, lParam, true); 
       handled = true; 
      }      
      break; 
    } 
    return (IntPtr)0; 
} 


//all the helpers for dealing with this COM crap 
[DllImport("user32")] 
internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi); 

[DllImport("user32")] 
internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags); 

private const int MonitorDefaultToNearest = 0x00000002; 

[StructLayout(LayoutKind.Sequential)] 
public struct WINDOWPOS 
{ 
    public IntPtr hwnd; 
    public IntPtr hwndInsertAfter; 
    public int x; 
    public int y; 
    public int cx; 
    public int cy; 
    public int flags; 
} 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
public class MONITORINFO 
{ 
    public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); 
    public RECT rcMonitor; 
    public RECT rcWork; 
    public int dwFlags; 
} 

[StructLayout(LayoutKind.Sequential, Pack = 0)] 
public struct RECT 
{ 
    public int left; 
    public int top; 
    public int right; 
    public int bottom; 
} 
+0

Upvoted puramente per il tuo commento "tutti gli aiutanti per affrontare questa merda COM" ... –

Problemi correlati