2010-09-07 14 views
12

Sto cercando di automatizzare una sequenza di input utente in un'applicazione compilata in C# utilizzando l'API Win32. Non ho alcun codice sorgente per l'applicazione che sto cercando di controllare ed è in esecuzione mentre sto cercando di controllarlo. Nel mio codice, ho un unico pulsante che, se cliccato, ha bisogno di fare una sequenza di 3 ingressi per l'applicazione che sto cercando di controllare:Come selezionare un elemento in TreeView utilizzando l'API Win32

  1. seleziona un elemento in una vista ad albero
  2. Fare clic su un pulsante di
  3. clic su un altro pulsante

il modo in cui funziona è il pulsante al punto 2 esegue un'azione a seconda della voce selezionata nella vista ad albero nel passaggio 1. sono in grado di ottenere il pulsante scatti per funzionare bene con la semplice invio di un messaggio, ma non riesco a capire come selezionare l'oggetto TreeView che desidero. TreeView è statico, quindi gli elementi e il layout non cambieranno mai. Essa ha la seguente configurazione:

-itemsA
-itemsB
--itemB1
-itemsC

Dove itemB1 è l'elemento che deve essere selezionato in modo che gli scatti del tasto ai punti 2 e 3 lavorare. Per impostazione predefinita, ItemsB è compresso, quindi probabilmente dovrò espanderlo prima di poter selezionare ItemB1? Ecco il mio codice. Apprezzo qualsiasi aiuto!!

//Find Window API 
[DllImport("User32.dll")] 
public static extern Int32 FindWindow(String lpClassName, String lpWindowName); 

//Find WindowEx API 
[DllImport("user32.dll", SetLastError = true)] 
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle); 

//Send Message API 
[DllImport("user32.dll", CharSet = CharSet.Auto)] 
public static extern int SendMessage(int hWnd, int msg, int wParam, IntPtr lParam); 


private const int BN_CLICKED = 245; 

//Method called by button click 
public static void Start() 
{ 
    int hwnd = 0; 
    int prod = 0; 
    IntPtr hwndChild = IntPtr.Zero; 
    IntPtr treeChild = IntPtr.Zero; 
    IntPtr prodChild = IntPtr.Zero; 

    hwnd = FindWindow(null, "Application"); 
    if (hwnd > 0) 
    { 
     //Get Handle for TreeView, THIS IS WHERE I AM STUCK!! 
     treeChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "AfxMDIFrame80", null); 
     treeChild = FindWindowEx((IntPtr)treeChild, IntPtr.Zero, "AfxMDIFrame80", null); 
     treeChild = FindWindowEx((IntPtr)treeChild, IntPtr.Zero, "SysTreeView32", null); 
     //Need to Add code to select item in TreeView ??? 

     //Click First Button 
     hwndChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "AfxMDIFrame80", null); 
     hwndChild = FindWindowEx((IntPtr)hwndChild, IntPtr.Zero, "AfxMDIFrame80", null); 
     hwndChild = FindWindowEx((IntPtr)hwndChild, IntPtr.Zero, "#32770", null); 
     IntPtr scanBtn = FindWindowEx((IntPtr)hwndChild, IntPtr.Zero, "Button", "&Scan"); 
     SendMessage((int)scanBtn, BN_CLICKED, 0, IntPtr.Zero); 

     //Click Second Button 
     prod = FindWindow("#32770", "Product: WPC"); 
     prodChild = FindWindowEx((IntPtr)prod, IntPtr.Zero, "Button", "&Collect"); 
     SendMessage((int)prodChild, BN_CLICKED, 0, IntPtr.Zero); 
    } 
    }//END Start 

Hans,

potete darmi un esempio di come avrei fatto questo? Il problema che sto avendo è trovare l'handle per l'elemento treeview che desidero selezionare. Se uso Spy ++ per trovare la maniglia attuale e hardcode nel mio metodo, che funziona bene, in questo modo:

SendMessage((int)treeChild, TV_SELECTITEM, TVGN_CARET, (IntPtr)0x092DCB30); 

Se uso SendMessage e inviare TVGN_ROOT alla maniglia TreeView, sarà restituito un IntPtr con il manico per la voce da selezionare nella vista ad albero, o come funziona? Sto anche sperimentando con AutoIt, ma speravo di mantenere tutto il mio codice in un'unica applicazione.

risposta

11

L'ho capito, quindi post Ill per chiunque sia interessato, ho avuto difficoltà a trovare la documentazione su questo. Ecco la maggior parte del mio codice:

//Define TreeView Flags and Messages 
private const int BN_CLICKED = 0xF5; 
private const int TV_FIRST = 0x1100; 
private const int TVGN_ROOT = 0x0; 
private const int TVGN_NEXT = 0x1; 
private const int TVGN_CHILD = 0x4; 
private const int TVGN_FIRSTVISIBLE = 0x5; 
private const int TVGN_NEXTVISIBLE = 0x6; 
private const int TVGN_CARET = 0x9; 
private const int TVM_SELECTITEM = (TV_FIRST + 11); 
private const int TVM_GETNEXTITEM = (TV_FIRST + 10); 
private const int TVM_GETITEM = (TV_FIRST + 12); 

//Find Window API 
[DllImport("User32.dll")] 
public static extern Int32 FindWindow(String lpClassName, String lpWindowName); 

//Find WindowEx API 
[DllImport("user32.dll", SetLastError = true)] 
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle); 

//Send Message API 
[DllImport("user32.dll", CharSet = CharSet.Auto)] 
public static extern int SendMessage(int hWnd, int msg, int wParam, IntPtr lParam); 

public static void Start() 
     { 
      //Handle variables 
      int hwnd = 0; 
      int treeItem = 0; 
      IntPtr hwndChild = IntPtr.Zero; 
      IntPtr treeChild = IntPtr.Zero; 

      hwnd = FindWindow(null, "Application"); //Handle for the application to be controlled 
      if (hwnd > 0) 
      { 
       //Select TreeView Item 
       treeChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "AfxMDIFrame80", null); 
       treeChild = FindWindowEx((IntPtr)treeChild, IntPtr.Zero, "AfxMDIFrame80", null); 
       treeChild = FindWindowEx((IntPtr)treeChild, IntPtr.Zero, "SysTreeView32", null); 
       treeItem = SendMessage((int)treeChild, TVM_GETNEXTITEM, TVGN_ROOT, IntPtr.Zero); 
       treeItem = SendMessage((int)treeChild, TVM_GETNEXTITEM, TVGN_NEXT, (IntPtr)treeItem); 
       treeItem = SendMessage((int)treeChild, TVM_GETNEXTITEM, TVGN_CHILD, (IntPtr)treeItem); 
       SendMessage((int)treeChild, TVM_SELECTITEM, TVGN_CARET, (IntPtr)treeItem); 

       // ...Continue with my automation... 
      } 
     }//END Scan 

Ancora non riesco a capire questo 100%, ma speriamo che questo aiuti. Il valore restituito da SendMessage dipenderà dal messaggio che si sta inviando, in questo caso era un int contenente l'handle di un oggetto TreeView. Il primo argomento è l'handle per TreeView stesso. Il secondo argomento è il messaggio che si desidera inviare. Il 3 ° e il 4 ° argomento sono flag. il 3 ° indica il tipo di oggetto, il 4 è il quadrante della voce treeview corrente.

Grazie per l'aiuto Hans! Qualcun altro, per favore sentiti libero di elaborare.

2

Avrete bisogno di camminare i nodi con TVM_GETNEXTITEM, a partire da TVGN_ROOT. Quindi selezionalo con TVM_SELECTITEM. Passa il TVGN_FIRSTVISIBLE per assicurarti che sia visibile, non dovrebbe essere necessario se lo si automatizza.

Dai un'occhiata a AutoIt per evitare di scrivere codice grungy come questo.

+0

Potete darmi un esempio di come farei questo? Il problema che sto avendo è trovare l'handle per l'elemento treeview che desidero selezionare. Se utilizzo Spy ++ per trovare l'handle corrente e lo codifico nel mio metodo, funziona correttamente, come questo: SendMessage ((int) treeChild, TV_SELECTITEM, TVGN_CARET, (IntPtr) 0x092DCB30); Se utilizzo SendMessage e invio TVGN_ROOT all'handle TreeView, restituirà un IntPtr con l'handle per l'elemento da selezionare nella visualizzazione ad albero, o come funziona? Sto anche sperimentando con AutoIt, ma speravo di mantenere tutto il mio codice in un'unica applicazione. – user441603

+0

TVGN_ROOT è un flag, non un messaggio. TVM_GETNEXTITEM è il messaggio. Se vuoi aiuto con il tuo codice, pubblicalo nella tua domanda. –

+0

Il mio errore. Pubblicazione prima volta al forum. – user441603

0

So che è abbastanza tardi, ma se si verifica un problema simile (come lo sono io). Potresti dare un'occhiata a AutoHotKey, specialmente se hai familiarità con SendMessage. Ciò ti farebbe risparmiare la necessità di compilare e molta complessità, ma al tuo punto sarebbe possibile navigare attraverso la struttura usando i tasti freccia.

Problemi correlati