Visualizzazione dei risultati da 1 a 4 su 4
  1. #1
    Utente di HTML.it
    Registrato dal
    Aug 2004
    Messaggi
    69

    [c#/c++] Eseguire un'applicazione esterna dentro una form

    Salve,

    una premessa: non sto chiedendo come si esegue un programma esterno. Questo lo so già fare. Ho già guardato un sacco di post qui sul forum e tutti putroppo si riferiscono alla semplice esecuzione di programmi esterni.

    Dunque io ho la necessità di eseguire un'applicazione esterna all'interno di una mia form, per la precisione dentro un suo pannello. In altre parole vorrei emulare una sorta di applicazione MDI in cui però le finestre child della principale (la mia applicazione) non sono form da me create, ma applicazioni esterne eterogenee, sul cui codice non ho alcun controllo quindi! Ho guardato un sacco di forum sul web e la cosa è fattibile, ma putroppo tutti gli esempi funzionanti eseguono applicazioni di windows come notepad o la calcolatrice. Queste applicazioni funzionano anche a me nella maniera voluta e questo fa ben sperare. Putroppo però non sempre le cose funzionano. Ad esempio con eseguibili come iexplore.exe (Internet Explorer) o write.exe (Wordpad) succede che l'applicazione esterna viene lanciata ma non viene "inglobata" nella mia form.

    Tecnicamente quello che sul web indicano di fare è di usare alcune funzioni win-api dichiarandole esterne dentro il proprio codice "managed" in C# o C++ (o VB.NET).

    Ecco un esempio del mio codice FUNZIONANTE (notate che eseguo appunto notepad.exe)
    codice:
    // dichiarazione delle funzioni esterne win-api
    public:
    [DllImport("USER32.DLL")]
    static int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
    static bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
    
    // setting del processo da lanciare
    System::Diagnostics::ProcessStartInfo^ psi = gcnew System::Diagnostics::ProcessStartInfo();
    psi->WindowStyle = System::Diagnostics::ProcessWindowStyle::Normal;
    psi->FileName = "notepad.exe";
    psi->Arguments = "";
    psi->UseShellExecute = false;
    System::Diagnostics::Process^ proc = System::Diagnostics::Process::Start(psi);
    
    // il thread della mia applicazione attende INDEFINITAMENTE fino a quando l'applicazione
    // esterna è stata inizializzata correttamente
    bool wait = proc->WaitForInputIdle();
    
    // imposto l'handle della finestra della nuova applicazione lanciata come child di
    // un pannello della mia form
    IntPtr gpsHandle = proc->MainWindowHandle;
    SetParent(gpsHandle, panel3->Handle);
    MoveWindow(gpsHandle, 0, 0, panel3->Width, panel3->Height, true);
    this->panel3->ResumeLayout();
    this->panel3->PerformLayout();
    this->ResumeLayout();
    this->PerformLayout();
    Il codice sopra funziona correttamente. Viene lanciato il notepad e la finestra viene inglobata nel pannello della mia form. Ma se si prova a cambiare eseguibile le cose non sempre funzionano. E' come se la funzione WaitForInputIdle() non riesca sempre ad attendere il tempo necessario affinchè la nuova finestra venga inglobata. Con notepad.exe funziona. Con iexplore.exe ad esempio no. Con le applicazioni che devo utilizzare non funziona e queste semplicemente vengono eseguite ma non inglobate. Nei casi in cui le cose funzionano il valore assegnato a gpsHandle è un valore numerico positivo (suppongo un puntatore interno). Nei casi in cui non funziona, gpsHandle è 0 (ma pensa un po'...). Ho indagato anche sul ritorno di WaitForInputIdle e questa procedura ritorna true se la nuova finestra è pronta, false altrimenti. Ma nel mio caso l'attesa dovrebbe essere indefinita e quindi dle tutto bloccante. Invece la procedura ritorna sempre true, anche se poi la finestra non viene inglobata nella mi form.

    Ma ecco un trucco strano. Basta sostituire la chiamata alla WaitForInputIdle() con una stupida sleep e tutto funziona. Il problema però è che io non posso sapere a priori quanto sia necessario attendere per una generica applicazione esterna da eseguire. Ho fatto delle prove e con una sleep di 300ms per ora funzionano tutte le applicazioni che ho provato. Con 100ms solo alcune... insomma è un casino!

    In definitiva sembra quasi che il processo con la nuova applicazione esterna venga lanciato. Poi però il chiamante (la mia form) non rimane bloccato sulla WaitForInputIdle per un lasso di tempo sufficiente affinché l'handle della finestra associata all'applicazione esterna sia stato correttamente inizializzato. Questo sembra essere erroneo però, perchè la WaitForInputIdle, in mancanza di parametri espliciti, attende il processo chiamato per un tempo indefinito. Invece nel mio caso ritorna sempre immediatamente con valore true, come se avesse rilevato che la finestra dell'applicazione esterna sia stata inizializzata correttamente... anche se poi l'handle rimane a 0! Ovviamente ho anche provato a chiamare WaitForInputIdle passando come parametro il tempo di attesa, ma anche con valori molto alti la funzione ritorna immediatamente, fregandosene altamente insomma!

    Potete aiutarmi? Qualcuno sa perchè questa procedura non fa il suo lavoro in alcune circostanze? Perchè con la sleep() le cose funzionano?

    Grazie

  2. #2
    Utente di HTML.it L'avatar di Stoicenko
    Registrato dal
    Feb 2004
    Messaggi
    2,254
    Da msdn la funzione che cerchi di usare va bene se il processo utilizza un message loop e quindi effettivamente attende che finisca l'idle.. ma se non ce l'ha ritorna subito true..

  3. #3
    Utente di HTML.it L'avatar di gibra
    Registrato dal
    Apr 2008
    residenza
    Italy
    Messaggi
    4,244
    La butto lì (non ho mai provato), ma potrebbe essere benissimo che la creazione del'handle del programma che avvi non sia così immediata e veloce come nel caso di un banale programma come il Notepad o la calcolatrice.

    Se metti la Sleep() PRIMA (e NON al posto) di WaitForInputIdle() cosa succede?

    Ciao

  4. #4
    Utente di HTML.it
    Registrato dal
    Aug 2004
    Messaggi
    69
    Originariamente inviato da gibra
    La butto lì (non ho mai provato), ma potrebbe essere benissimo che la creazione del'handle del programma che avvi non sia così immediata e veloce come nel caso di un banale programma come il Notepad o la calcolatrice.

    Se metti la Sleep() PRIMA (e NON al posto) di WaitForInputIdle() cosa succede?

    Ciao
    Infatti è probabile che i programmi che avvio non siano così rapidi ad avviarsi come notepad o altro. Ed infatti il sistema non funziona anche con applicazioni come internet explorer o wordpad. La sleep() posso tranquillamente metterla prima della waitforinputidle() o metterla al suo posto e, se l'intervallo specificato nella sleep è sufficientemente ampio, il tutto funziona correttamente. Dirò di più. Con notepad, che funziona anche senza sleep(), posso tranquillamente fare a meno sia della sleep() che della waitforinputidle()!!! Insomma sembra che questa waitforinputidle() non sia bloccante come in realtà dovrebbe essere. La procedura ritorna sempre immediatamente true fregandosene altamente se l'applicazione che lancio sia pesante o meno.



    Da msdn la funzione che cerchi di usare va bene se il processo utilizza un message loop e quindi effettivamente attende che finisca l'idle.. ma se non ce l'ha ritorna subito true..
    E' vero che la funzione WaitForInputIdle funziona solo con processo che abbiano un message loop associato o in altre parole, con processi che abbiano una finestra grafica associata. Ma hai probabilmente letto male. Se il programma non ha un message loop la procedura ritorna immediatamente FALSE, mentre ne mio caso torna sempre immediatamente true. Per di più ho fatto una prova lanciando un eseguibile tramite console e infatti la procedura solleva un eccezione e l'errore visualizzato dice chiaramente che il processo non ha una interfaccia grafica associata. In quel caso la WaitForInputIdle ritorna "correttamente" false immediatamente.

    Qui la cosa diventa misteriosa a mio parere.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.