none
aprire pagina html solo se non è già aperta RRS feed

  • Domanda

  • Buongiorno a tutti,

    da un programma vb net al verificarsi di un evento apro una pagina html nel browser predefinito con Process.Start(indirizzo).

    Funziona tutto correttamente ma io vorrei prima verificare se la pagina è già aperta e, in tal caso, non riaprirla e portare in primo piano quella già in uso. Qualcuno sa indicarmi come si fa?

    Grazie 1000.

    Beppe

    giovedì 4 giugno 2020 13:49

Risposte

  • In realtà quello che ti proponevo è meno complesso di quello che sembra inizialmente, perlomeno con i browser che ho provato.

    Un esempio in c# (net core 3.1):

    public static class WindowHelper
        {
            public static void OpenURL(this IEnumerable<string> browserList, Uri uri)
            {
                bool found = false;
                var processes = browserList.SelectMany(s => Process.GetProcessesByName(s)).Where(a => !string.IsNullOrWhiteSpace(a.MainWindowTitle));
                foreach (var process in processes)
                {
                    BringProcessToFront(process);
                    var uia = new CUIAutomation();
                    var root = uia.ElementFromHandle(process.MainWindowHandle);
                    var tabs = root.FindAll(
                        TreeScope.TreeScope_Subtree,
                        uia.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_TabItemControlTypeId)
                    );
                    if (tabs.Length > 0)
                    {
                        var targetList = Enumerable.Range(0, tabs.Length).Select(s => tabs.GetElement(s));
                        foreach (var tg in targetList)
                        {
                            tagPOINT point = new tagPOINT();
                            tg.GetClickablePoint(out point);
                            SetCursorPos(point.x + 15, point.y + 15);
                            MouseClick(point.x + 15, point.y + 15);
                            var searchBarList = uia.ElementFromHandle(process.MainWindowHandle).FindAll(TreeScope.TreeScope_Children | TreeScope.TreeScope_Element | TreeScope.TreeScope_Subtree, uia.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_EditControlTypeId));
                            var urls = Enumerable.Range(0, searchBarList.Length).Select(i => (string)searchBarList.GetElement(i).GetCurrentPropertyValue(Interop.UIAutomationClient.UIA_PropertyIds.UIA_ValueValuePropertyId));
                            var url = $"{uri.Host}{uri.PathAndQuery}{uri.Fragment}";
                            found = urls.Any(a => a.Contains(url));
                            if (found)
                                break;
                        }
                    }
                    if (found)
                        break;
                }
                if (!found)
                {
                    ProcessStartInfo psi = new ProcessStartInfo
                    {
                        FileName =uri.AbsoluteUri,
                        UseShellExecute = true
                    };
                    Process.Start(psi);
                }
            }
            public static void BringProcessToFront(Process process)
            {
                IntPtr handle = process.MainWindowHandle;
                if (IsIconic(handle))
                    ShowWindow(handle, 9);
                SetForegroundWindow(handle);
            }
            [System.Runtime.InteropServices.DllImport("User32.dll")]
            private static extern bool SetForegroundWindow(IntPtr handle);
            [System.Runtime.InteropServices.DllImport("User32.dll")]
            private static extern bool ShowWindow(IntPtr handle, int nCmdShow);
            [System.Runtime.InteropServices.DllImport("User32.dll")]
            private static extern bool IsIconic(IntPtr handle);
            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
            public static extern void mouse_event(uint dwFlags, int dx, int dy, int dwData, int dwExtraInfo);
            [DllImport("user32.dll")]
            public static extern long SetCursorPos(int x, int y);        
            public static void MouseClick(int x, int y)
            {
                mouse_event(0x0002 | 0x0004, x, y, 0, 0);
            }
        }

    In pratica cerco tra i processi se ci sono browser conosciuti (tra quelli in lista) attivi, in caso positivo li itero e per ognuno porto in primo piano la finestra del browser e controllo se ci sono indirizzi corrispondenti a quello desiderato, in caso positivo muovo il mouse verso l'elemento e faccio click per darli il focus. Nel caso non ci sia nessun indirizzo corrispondente avvio il browser predefinito in quel url.

    Per usarlo basta questo :

    new[] { "chrome", "firefox", "msedge" }.OpenURL(new Uri("https://dominio.it/pagina.html"));

    Se c'è già una scheda aperta allora porta in primo piano quella, diversamente apre una nuova finestra a quel indirizzo.

    Ovviamente puoi aggiungere o togliere browser dall'array.







    • Modificato U 235 sabato 6 giugno 2020 03:35
    • Contrassegnato come risposta Beppe1964 sabato 6 giugno 2020 08:12
    venerdì 5 giugno 2020 22:32

Tutte le risposte

  • Ciao Beppe1964,

    Ci possono essere diversi modi per ottenere quello che vuoi, ad esempio potresti controllare se è presente un processo del browser (o dei vari browser installati) attivo e controllare il titolo. Oppure avendo indirizzo ip (se si tratta di un unica pagina) potresti controllare le connessioni attive e cercare eventualmente una connessione a quel'host. Ovviamente in quest'ultimo caso non hai una pagina specifica, ma una connessione allo specifico host.

    Ad esempio con c# valutare se tra i processi di chrome firefox o msedge vi sono titoli aperti con lo stesso titolo della pagina web di cui vorrei valutare l'apertura è abbastanza semplice:

    var title = "titolo pagina web";
    var isOpen= new[] { "chrome", "firefox", "msedge" }.Any(a => Process.GetProcessesByName(a).Any(aa => aa.MainWindowTitle.ToLower().Contains(title)));

    Ma i problemi iniziano se l'utente ha la pagina aperta in un processo, ma la scheda che ha il focus non è quella della pagina interessata, a questo punto il sistema fallisce in quanto nel titolo della finestra ci sarà quello della scheda che sto osservando (che ha il focus nel processo analizzato). Inoltre dovresti controllare tutti i browser che ha l'utente.

    Il secondo metodo potrebbe essere quello di valutare se vi è una connessione diretta ad uno specifico host. 

    Ad esempio sempre in c#:

    var host = Dns.GetHostAddresses("dominio.it");
    var isOpen = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections().Any(a => a.State == TcpState.Established && host.Contains(a.RemoteEndPoint.Address));

    Ma potrebbe essere complicato in alcuni casi trovare l'ip giusto.

    Al momento non mi viene in mente altro, anche perché dipende dalla tua esigenza potrebbe anche essere già sufficiente (magari unendo i due controlli).

    EDIT:

    Ho letto meglio ed avevo tralasciato una pezzo importante : "...e portare in primo piano quella già in uso.". Questo ovviamente rende più complesso il tutto...

    Analizzando l'interfaccia del browser si può ottenere qualsiasi elemento distinguibile (compreso l'indirizzo della scheda) ed eventualmente si può pilotare sia tramite "AutomationElement" (parliamo sempre di NET in questo caso) anche eventualmente emulando il mouse e portandolo (tramite coordinate prese dall'interfaccia grafica) sulla scheda per fare click (dopo aver portato in primo piano il browser contenente la scheda).

    In questo caso però dovrai fare un bel po di lavoro e pure su diversi browser...



    • Modificato U 235 venerdì 5 giugno 2020 16:37
    venerdì 5 giugno 2020 16:14
  • Ciao U 235 e grazie per la risposta.

    Purtroppo non so il titolo della pagina html che non sono io a gestire.

    Io ho a disposizione l'indirizzo in cui si trova la pagina (www.pippo.it/abcd) che è una variabile che leggo da un db e poi mi costruisco il path completo con il nome della form attiva: quindi se sono sulla Form1 dovrò aprire www.pippo.it/abcd/Form1.html.

    Per cui a me basterebbe avere da qualche parte disponibili gli url aperti nel browser di default e scorrerli per verificare se è presente quello che devo controllare. Se poi è troppo complicato portare la pagina in primo piano se già aperta posso anche limitarmi a dare un messaggio LA PAGINA RICHIESTA È GIÀ APERTA e andrebbe bene ugualmente....

    Questo si può fare?

    Grazie 1000.

    Beppe

    venerdì 5 giugno 2020 20:10

  • Dovresti suddividere i problemi.

    Il primo è capire se hai qualcosa già aperto nel browser, ma questo non è così semplice determinarlo se non hai un riferimento come titolo del processo. Quindi a questo punto tanto vale controllare i processi dei browser e dal loro handler recuperare l'elemento di UI Automation, da qui iniziare a cercare ad esempio la barra degli indirizzi e da li leggere la label e confrontarlo.

    Non so se riesci a leggere anche gli indirizzi non visibili delle altre schede senza il focus, ma nel caso dovresti provvedere a cambiare focus tramite simulazione del mouse, a quel punto lo tratti come tratti la scheda con il focus e ne leggi l'indirizzo nella barra. Se c'è corrispondenza hai già lanciato anche il focus in questo caso. Diversamente se non è necessario dare il focus per leggere l'indirizzo, ovviamente il focus lo dai se trovi corrispondenza.

    IU Automation ti consente di impostare il focus, ma nel caso puoi anche recuperare il punto cliccabile e usare il simulatore di input e fare click con il mouse.

    Uno strumento utile per vedere "l'albero" degli elementi dell'interfaccia dei vari browser (o comunque programmi con interfaccia grafica), in modo da non cercare gli elementi alla cieca nel codice è inspect.exe, che puoi trovare in windows kits. 

    Ad esempio aprendo inspect potrai notare un quadrato giallo nella barra, se lo clicchi puoi andare con il mouse su un elemento del browser (tipo la barra dell'indirizzo), a quel punto ti crea un quadrato giallo intorno all'elemento e contemporaneamente dentro inspect verranno aperti i nodi nella posizione ad albero degli elementi, tramite quelli potrai risalire a dove trovare esattamente l'indirizzo nell'albero. Potrai ad esempio leggere il tipo di controllo per cercare tramite query mirate (solo quel tipo di controllo) oppure magari altri riferimenti che ti rendono più semplice localizzare gli elementi dell'interfaccia del browser.

    Se vuoi inizia a scrivere qualcosa, nel caso abbia problemi chiedi pure.

    Ti auguro buon lavoro.

    EDIT:

    Qualcuno pare abbia già affrontato il problema : qui e forse c'è un metodo diverso.



    • Modificato U 235 venerdì 5 giugno 2020 22:54
    venerdì 5 giugno 2020 21:14
  • In realtà quello che ti proponevo è meno complesso di quello che sembra inizialmente, perlomeno con i browser che ho provato.

    Un esempio in c# (net core 3.1):

    public static class WindowHelper
        {
            public static void OpenURL(this IEnumerable<string> browserList, Uri uri)
            {
                bool found = false;
                var processes = browserList.SelectMany(s => Process.GetProcessesByName(s)).Where(a => !string.IsNullOrWhiteSpace(a.MainWindowTitle));
                foreach (var process in processes)
                {
                    BringProcessToFront(process);
                    var uia = new CUIAutomation();
                    var root = uia.ElementFromHandle(process.MainWindowHandle);
                    var tabs = root.FindAll(
                        TreeScope.TreeScope_Subtree,
                        uia.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_TabItemControlTypeId)
                    );
                    if (tabs.Length > 0)
                    {
                        var targetList = Enumerable.Range(0, tabs.Length).Select(s => tabs.GetElement(s));
                        foreach (var tg in targetList)
                        {
                            tagPOINT point = new tagPOINT();
                            tg.GetClickablePoint(out point);
                            SetCursorPos(point.x + 15, point.y + 15);
                            MouseClick(point.x + 15, point.y + 15);
                            var searchBarList = uia.ElementFromHandle(process.MainWindowHandle).FindAll(TreeScope.TreeScope_Children | TreeScope.TreeScope_Element | TreeScope.TreeScope_Subtree, uia.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_EditControlTypeId));
                            var urls = Enumerable.Range(0, searchBarList.Length).Select(i => (string)searchBarList.GetElement(i).GetCurrentPropertyValue(Interop.UIAutomationClient.UIA_PropertyIds.UIA_ValueValuePropertyId));
                            var url = $"{uri.Host}{uri.PathAndQuery}{uri.Fragment}";
                            found = urls.Any(a => a.Contains(url));
                            if (found)
                                break;
                        }
                    }
                    if (found)
                        break;
                }
                if (!found)
                {
                    ProcessStartInfo psi = new ProcessStartInfo
                    {
                        FileName =uri.AbsoluteUri,
                        UseShellExecute = true
                    };
                    Process.Start(psi);
                }
            }
            public static void BringProcessToFront(Process process)
            {
                IntPtr handle = process.MainWindowHandle;
                if (IsIconic(handle))
                    ShowWindow(handle, 9);
                SetForegroundWindow(handle);
            }
            [System.Runtime.InteropServices.DllImport("User32.dll")]
            private static extern bool SetForegroundWindow(IntPtr handle);
            [System.Runtime.InteropServices.DllImport("User32.dll")]
            private static extern bool ShowWindow(IntPtr handle, int nCmdShow);
            [System.Runtime.InteropServices.DllImport("User32.dll")]
            private static extern bool IsIconic(IntPtr handle);
            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
            public static extern void mouse_event(uint dwFlags, int dx, int dy, int dwData, int dwExtraInfo);
            [DllImport("user32.dll")]
            public static extern long SetCursorPos(int x, int y);        
            public static void MouseClick(int x, int y)
            {
                mouse_event(0x0002 | 0x0004, x, y, 0, 0);
            }
        }

    In pratica cerco tra i processi se ci sono browser conosciuti (tra quelli in lista) attivi, in caso positivo li itero e per ognuno porto in primo piano la finestra del browser e controllo se ci sono indirizzi corrispondenti a quello desiderato, in caso positivo muovo il mouse verso l'elemento e faccio click per darli il focus. Nel caso non ci sia nessun indirizzo corrispondente avvio il browser predefinito in quel url.

    Per usarlo basta questo :

    new[] { "chrome", "firefox", "msedge" }.OpenURL(new Uri("https://dominio.it/pagina.html"));

    Se c'è già una scheda aperta allora porta in primo piano quella, diversamente apre una nuova finestra a quel indirizzo.

    Ovviamente puoi aggiungere o togliere browser dall'array.







    • Modificato U 235 sabato 6 giugno 2020 03:35
    • Contrassegnato come risposta Beppe1964 sabato 6 giugno 2020 08:12
    venerdì 5 giugno 2020 22:32
  • Ciao U 235 e grazie per la risposta.

    Non pensavo fosse una cosa così laboriosa, tra l'altro la richiesta del cliente era semplicemente di aprire la pagina recuperando path e nome come ho descritto, poi ho pensato di aggiungere questa cosa immaginando fosse semplice. Per il momento consegno così. 

    Nel frattempo mi guardo con calma la funzione che hai sviluppato e in un secondo momento la aggiungerò.

    Grazie ancora per l'aiuto!

    Buon fine settimana.

    Beppe

    sabato 6 giugno 2020 08:12
  • Ciao 👋 Non so se c’è un modo più semplice per ottenere tutte le connessioni “aperte”. Il problema è che parliamo di http che di per se è state less, quindi la connessione viene aperta per scaricare il contenuto è dopo si chiude, quindi non dovrebbe rimanere traccia se non dove hai scaricato (nel browser salvo non venga tracciato esternamente come poi stiamo facendo con questo). In ogni caso anche se esistesse un luogo dove prendere le info delle ultime richieste (diciamo ultime pagine richieste) non ci sarebbe nessuna garanzia che questa sia ancora aperta nel browser.
    • Modificato U 235 sabato 6 giugno 2020 12:00
    sabato 6 giugno 2020 11:41