Questo sito utilizza i cookie per migliorare servizi ed esperienza del lettore. Se decidi di continuare la navigazione consideriamo che accetti il loro uso . Per e informazioni sulla Privacy leggere la Google Policies Privacy

Se continui nella navigazione accetti il loro uso. OK

martedì 24 agosto 2010

WPFNotes (Parte 2): Un po' di API Win32

Vediamo ora come aggiungere due funzionalità essenziali per l'applicazione:
  • Filtrare le note in base alle finestre che sono aperte in windows
  • Filtrare le note in base alla finestra attiva per dare maggiore priorità alle note contestuali
Per svolgere queste due operazioni dobbiamo utilizzare alcune funzioni di windows perchè il .NET non ci mette a disposizione questo genere di funzionalità. Partiamo con la più facile: trovare la finestra attiva e leggere la sua Caption. Le funzioni api che ci servono sono due:
GetForegroundWindow e GetWindowText. La prima ci permette di reperire la finestra attiva su cui sta lavorando l'utente (in pratica la funzione cerca la finestra attiva che ha la priorità leggermente più alta, cosa che viene fatat da windows per le finestre in Foreground).
La seconda invece invia un messaggio WM_GETTEXT a un determinato handle di finestra (Nota: non funziona con i controlli ospitati in altre finestre, ma con i caption delle window sì, cosa che per noi va benissimo!).
Vediamo di scrivere le due firme delle funzioni (copiate da msdn):

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetForegroundWindow();
Quello che ora dobbiamo scrivere è una funzione che, eseguita in polling con un timer ci permetta di sapere sempre quel'è la finestra attiva:
/// 
/// Restituisce il caption della finestra specificata.
/// 
const int MAXTITLE = 255;
public static string GetWindowText(IntPtr hWnd) {
    StringBuilder titolo = new StringBuilder(MAXTITLE);
    int titleLength = GetWindowText(hWnd, titolo, titolo.Capacity + 1);
    titolo.Length = titleLength;

    return titolo.ToString();
}

//Reperisce la finestra attiva e ne legge la caption
IntPtr ptr = EnumerateWindow.GetForegroundWindow();
if (ptr!=IntPtr.Zero)
    CurrentWindowText = EnumerateWindow.GetWindowText(ptr);
Fin qui tutto semplice. Vediamo adesso di risolvere un problema più complesso: la lettura di tutti i caption delle finestre che sono aperte.
Per svolgere questa operazione di avvaliamo della funzione EnumDesktopWindows. La funzione accetta 3 parametri. Il primo è il desktop su cui eseguire la ricerca (NULL per eseguire la ricerca nel desktop corrente), una funzione call back (EnumWindowsProc) che verrà richiamata ad ogni nuova finestra trovata e un lParam che verrà passato alla funzione di callback. Vediamo le dichiarazioni:
private delegate bool EnumDelegate(IntPtr hWnd, int lParam);

[DllImport("user32.dll", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDelegate lpEnumCallbackFunction, IntPtr lParam);

private static ArrayList listaTitoli;
/// 
/// Restituisce i caption di tutte le finestre nel desktop di windows
/// 
public static string[] GetDesktopWindowsCaptions() {
    listaTitoli = new ArrayList();
    EnumDelegate delegateFunction = new EnumDelegate(EnumWindowsProc);
    bool success = EnumDesktopWindows(IntPtr.Zero, delegateFunction, IntPtr.Zero);

    if (success) {
        // Copia il risultato in un'array di stringhe
        string[] titoli = new string[listaTitoli.Count];
        listaTitoli.CopyTo(titoli);
        return titoli;
    }
    else {
        // ERRORE
        int errore = Marshal.GetLastWin32Error();
        string errorMessage = String.Format("EnumDesktopWindows ha fallito con errore: {0}.", errore);
        throw new Exception(errorMessage);
    }
}
private static bool EnumWindowsProc(IntPtr hWnd, int lParam) {
    string titolo = GetWindowText(hWnd);
    if (titolo != "")
        listaTitoli.Add(titolo);
    return true;
}
Chiaramente la funzione di ricerca può essere resa più efficiente andando a cercare solo caption con determinate caratteristiche. Ma questo lo lascio alla vostra fantasia.

WPFNotes (Parte 1): Progettazione applicazione e Database

Nessun commento:

Posta un commento