Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια
σε

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

Απ: EventHanlder Crash

Îåêßíçóå áðü ôï ìÝëïò nuclear. Τελευταία δημοσίευση από το μέλος nuclear στις 27-06-2011, 15:55. Υπάρχουν 7 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  22-06-2011, 20:02 66357

    Απ: EventHanlder Crash

    Γράφω εδώ την απορία μου μιας και ταιριάζει με το πρόβλημα του g1024:

    Από τη φόρμα μου κάνω instance μιας κλάσης η οποία ξεκινάει ένα 2ο λογισμικό προσομοίωσης (dos) το οποίο όταν τελειώσει δημιουργεί κάποια αρχεία. Για να γνωρίζω πότε τελείωσε η προσομοίωση πρόσθεσα στην κλάση ένα FileSystemWatcher για να παρακολουθεί πότε θα δημιουργηθεί το τελικό logfile και με ειδοποιεί με messagebox.

    Έχω πειραματιστεί με διάφορες διατάξεις και ενώ κάποιες φορές έχει δουλέψει μια χαρά, δεν είναι αξιόπιστο (δουλεύει στο deleted και όχι στο created). Πρόσθεσα το FileSystemWatcher στην φόρμα μου μαζί με statusstrip μήπως λειτουργήσει αξιόπιστα αλλά τότε κλείνει η εφαρμογή χωρίς μήνυμα λάθους όπως περιέγραψε ο g1024.

    Ψάχνοντας διάβασα ότι το FileSystemWatcher δεν είναι αξιόπιστο αλλά πουθενά δεν βρήκα να τους πετάει έξω από την εφαρμογή χωρίς μήνυμα λάθους. Μετά σκέφτηκα μήπως φταίει το messagebox και το depedency στο System.Windows (τώρα ξεκινώ προγραμματισμό και δεν κατάλαβα τι εννοεί) και το έβγαλα άλλα πάλι με πετάει.

    Τελικά βρήκα ότι το messagebox δουλεύει καλά μέσα από τη φόρμα (deleted και created) αλλά με πετάει έξω όταν πάει στην εντολή:

    statusStrip1.Text = "deleted";

    Δοκίμασα και με label και πάλι με πετάει χωρίς μήνυμα λάθους

    StatusLabel.Text = "deleted";

    Μοιάζει σαν bug του visual studio. Μήπως κάνω κάτι λάθος?

     

  •  22-06-2011, 20:16 66358 σε απάντηση της 66357

    Απ: EventHanlder Crash

    Σκέφτηκα ότι ίσως να είναι θέμα threading οπότε έβαλα την εξής εντολή και δουλεύει καλά:

    CheckForIllegalCrossThreadCalls = false;

    Από ότι γνωρίζω δεν πρέπει όμως να το απενεργοποιούμε γιατί είναι για να μας προστατεύει.

    Πως είναι η σωστή προσέγγιση?

     

  •  22-06-2011, 21:10 66359 σε απάντηση της 66358

    Απ: EventHanlder Crash

    Αντί να ψάχνεις για bug του Visual Studio καλύτερα να κοιτάξεις τί σκάει. Διαφορετικά απλά μαντεύεις. Τί exception πέφτει? Το γράφεις πουθενά? Το σκάσιμο συμβαίνει και όταν κάνεις debug? Τί σου λέει? 

    Αν το σκάσιμο συμβαίνει μόνο όταν τρέχει η εφαρμογή σου εκτός Visual Studio φρόντισε να βάλεις exception handlers και να γράψεις κάπου το exception, π.χ. σε ένα log file. 

    Και το FileSystemWatcher και το messagebox και όλα δουλεύουν πολύ καλά. Ούτε υπάρχει θέμα threading - εκτός και αν έχεις ξεκινήσει εσύ κάποιο thread ή χρησιμοποιείς ασύγχρονες κλήσεις. Από τη στιγμή όμως που δεν δίνεις κανένα απολύτως στοιχείο είναι αδύνατο να σε βοηθήσει κανείς. Το σίγουρο είναι πάντως ότι ΑΠΑΓΟΡΕΥΕΤΑΙ να φτιάξεις ένα control σε ένα thread (π.χ. στο main thread της εφαρμογής) και να πας μετά να το πειράξεις από άλλο (π.χ. μέσα από ένα ασύγχρονο delegate). Η απαγόρευση αυτή ισχύει από καταβολής Windows οπότε μιλάμε για περίπου 15-20 χρόνια. 

    Αν αυτή είναι η περίπτωση, θα πρέπει να ειδοποιήσεις το thread που έφτιαξε το control να κάνει την τροποποίηση αντί να το πειράξεις από το δεύτερο thread. Ο τρόπος που μπορεί να γίνει αυτό περιγράφεται στο How To : Make Thread-Safe calls to Windows Form Controls. Χονδρικά, καλείς την InvokeRequired επάνω στο control που θέλεις να πειράξεις και αν γυρίσει true καλείς την Invoke πάνω στο ίδιο control δίνοντας ως παράμετρο μία συνάρτηση η οποία πειράζει το control. Η Invoke θα αναλάβει να την καλέσει στο σωστό control. Όπως δείχνει και το παράδειγμα μπορείς να τα μαζέψεις όλα αυτά σε ένα απλό function όπως η SetText του άρθρου:

    delegate void SetTextCallback(string text);
    
    private void SetText(string text)
    {
    	// InvokeRequired required compares the thread ID of the
    	// calling thread to the thread ID of the creating thread.
    	// If these threads are different, it returns true.
    	if (this.textBox1.InvokeRequired)
    	{	
    		SetTextCallback d = new SetTextCallback(SetText);
    		this.Invoke(d, new object[] { text });
    	}
    	else
    	{
    		this.textBox1.Text = text;
    	}
    }


    Τέλος, θα πρότεινα να κοιτάξεις το documentation, τα How To και τα tutorials του MSDN αντί να ψάχνεις στο Internet τί λέει ο ένας και ο άλλος. Θα γλυτώσεις χρόνο και θα πελαγοδρομείς λιγότερο από το να προσπαθείς να καταλάβεις τί γράφει ο ένας και ο άλλος, ο οποίος μπορεί και να μην ξέρει και τί λέει. Όσο πιο έμπειρος είναι κανείς τόσο περισσότερο ανατρέχει στο documentation και το Help.

    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  22-06-2011, 23:05 66360 σε απάντηση της 66357

    Απ: EventHanlder Crash

    Χμ... Πολύ ενδιαφέρον αυτό που προσπαθείς να πετύχεις. Μήπως, όμως, ακολουθείς λάθος δρόμο; Ύστερα από λίγο ψάξιμο "έπεσα" πάνω σ' αυτή τη συζήτηση, ο οποία παραπέμπει σ' αυτή την πολύ ενδιαφέρουσα σελίδα του MSDN. Επίσης, θεωρώ ότι θα βρεις ενδιαφέρον και το άρθρο "Managing Processes in .NET" στο Code Magazine.

    Ακόμα κι ένας άνθρωπος μπορεί ν' αλλάξει τον κόσμο. Μη θέλεις να κυβερνήσεις. Απλά δείξε το μονοπάτι κι ο κόσμος θ' ακολουθήσει!!
  •  23-06-2011, 13:20 66362 σε απάντηση της 66360

    Απ: EventHanlder Crash

    Καταρχάς σας ευχαριστώ πολύ γιατί η βοήθειά σας ήταν καθοριστική και με καθοδήγησε ώστε να ξεκαθαρίσω πολλά θέματα.

    Το αρχικό μου πρόβλημα ήταν όντως τα διαφορετικά threads. Ο λόγος που δυσκολεύτηκα να το βρω είναι διότι το visual studio ΔΕΝ έβγαζε exception και γινόταν kill της εφαρμογής χωρίς καμία αναφορά σφάλματος. Αν είναι θέμα ρυθμίσεων VS, του έχω τις τυπικές ρυθμίσεις εγκατάστασης.

    Μάρκο ουσιαστικά αυτόν τον τρόπο χρησιμοποιώ αλλά με τα χρήσιμα link που έδωσες έμαθα και για το πολύ ενδιαφέρον RedirectStandardOutput. Παραθέτω το κομμάτι κώδικα και για άλλους χρήστες:

        class starteplus

        {

            public string StartEplus(string arguments)

            {

                //Νέα process

                Process myProcess = new Process();

                ProcessStartInfo psi = new ProcessStartInfo();

                //Όνομα εφαρμογής

                psi.FileName = @"c:\eplus\RunEPlus.bat";

                //Παράμετροι εφαρμογής

                psi.Arguments = filename;

                Directory.SetCurrentDirectory(@"c:\Test5\eplus1\");

                psi.RedirectStandardOutput = true;

                psi.UseShellExecute = false;

                //Κρύβει το dos window

                psi.CreateNoWindow = true;

                myProcess.StartInfo = psi;

                myProcess.Start();

                myProcess.WaitForExit();

                string result = myProcess.StandardOutput.ReadToEnd();

                return result;

            }

        }

    Αυτά που διαβάζονται από το StandardOutput.ReadToEnd() είναι stream. Με τον παραπάνω τρόπο διαβάζεται το σύνολο του stream αφού τελειώσει και επιστρέφει ως string. Επειδή με αυτό τον τρόπο δεν γίνεται καμία ενέργεια έως ότου να τελειώσει η myprocess (και μπορεί να πάρει αρκετό χρόνο), πως μπορώ να παίρνω γραμμή-γραμμή και να τα δείχνω στο gui μου ή σε άλλο παράθυρο (δηλαδή αυτά που θα έδειχνε σε dos shell να τα δείχνει στο gui καθώς εξελίσσονται)?

  •  23-06-2011, 18:02 66366 σε απάντηση της 66362

    Απ: EventHanlder Crash

    Από παλιά υλοποίηση μου - περιέχει όλο το puzzle του να καλέσεις ένα πρόγραμμα σε DOS και να πάρεις το output του:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
     
    public static class MediaController
    {
    	/// <summary>
    	/// Εκτελεί το ffmpeg με τις παραμέτρους που ορίζονται μέσα στο αντικείμενο MediaControllerArgs.
    	/// </summary>
    	/// <param name="Args">Η γραμμή εντολής του ffmpeg και οι παράμετροι που θέλουμε να του περάσουμε</param>
    	public static void RunCommand(MediaControllerArgs Args)
    	{
    		if (string.IsNullOrEmpty(Args.EncoderPath))
    			throw new ArgumentNullException("EncoderPath should not be null.");
    		if (string.IsNullOrEmpty(Args.EncoderArgs))
    			throw new ArgumentNullException("EncoderArgs should not be null.");
    		if (string.IsNullOrEmpty(Args.BinariesPath))
    			throw new ArgumentNullException("BinariesPath should not be null.");
    
    		using (Process p = new Process())
    		{
    			p.StartInfo.FileName = Args.EncoderPath;
    			p.StartInfo.Arguments = Args.EncoderArgs;
    			p.StartInfo.UseShellExecute = false;
    			p.StartInfo.RedirectStandardOutput = true;
    			p.StartInfo.RedirectStandardError = true;
    			p.StartInfo.CreateNoWindow = true;
    			p.StartInfo.ErrorDialog = false;
    			p.StartInfo.WorkingDirectory = Args.BinariesPath;
    			p.Start();
    
    			StandardStreamReader outputReader = new StandardStreamReader(p.StandardOutput);
    			StandardStreamReader errorReader = new StandardStreamReader(p.StandardError);
    			Thread outputReaderThread = new Thread(new ThreadStart(outputReader.Read));
    			Thread errorReaderThread = new Thread(new ThreadStart(errorReader.Read));
    			outputReaderThread.Start();
    			errorReaderThread.Start();
    
    			p.WaitForExit();
    			p.Close();
    
    			Args.OutputConsole = outputReader.Output;
    			Args.ErrorConsole = errorReader.Output;
    		}
    	}
    }
    
    public class MediaControllerArgs : EventArgs
    {
    	private string _BinariesPath;
    	private string _EncoderArgs;
    	private string _EncoderPath;
    	private string _ErrorConsole;
    	private string _OutputConsole;
    
    	public string EncoderPath
    	{
    		get { return _EncoderPath; }
    		set { _EncoderPath = value; }
    	}
    
    	public string EncoderArgs
    	{
    		get { return _EncoderArgs; }
    		set { _EncoderArgs = value; }
    	}
    
    	public string BinariesPath
    	{
    		get { return _BinariesPath; }
    		set { _BinariesPath = value; }
    	}
    
    	public string OutputConsole
    	{
    		get { return _OutputConsole; }
    		set { _OutputConsole = value; }
    	}
    
    	public string ErrorConsole
    	{
    		get { return _ErrorConsole; }
    		set { _ErrorConsole = value; }
    	}
    
    	public MediaControllerArgs()
    		: base()
    	{ }
    }
    
    internal class StandardStreamReader
    {
    	// Fields
    	private StringBuilder _reader = new StringBuilder();
    	private StreamReader _stdReader;
    
    	// Methods
    	public StandardStreamReader(StreamReader sr)
    	{
    		this._stdReader = sr;
    	}
    
    	public void Read()
    	{
    		int charCode = -1;
    		for (charCode = this._stdReader.Read(); charCode > 0; charCode = this._stdReader.Read())
    		{
    			this._reader.Append(Convert.ToChar(charCode));
    		}
    
    		Thread.CurrentThread.Abort();
    	}
    
    	// Properties
    	public string Output
    	{
    		get { return this._reader.ToString(); }
    	}
    }

    George J. Capnias: Χειροπρακτικός Υπολογιστών, Ύψιστος Γκουράρχης της Κουμπουτερολογίας
    w: capnias.org, t: @gcapnias, l: gr.linkedin.com/in/gcapnias
    dotNETZone.gr News
  •  23-06-2011, 18:09 66367 σε απάντηση της 66366

    Απ: EventHanlder Crash

    Βασικά, φαίνεται ότι χρησιμοποιώ ένα άλλο thread για να διαβάζω το output - είναι και προτινόμενος τρόπος για να κάνεις αυτό που θες.

    Μαζί με το StreamReader θα μπορούσες να περάσεις και το object που θα ήθελες να λαμβάνει και να απεικονίζει το text - προσοχή η λειτουργία θα είναι cross-thread και μπορεί να σε δυσκολέψει...

     

    George J.


    George J. Capnias: Χειροπρακτικός Υπολογιστών, Ύψιστος Γκουράρχης της Κουμπουτερολογίας
    w: capnias.org, t: @gcapnias, l: gr.linkedin.com/in/gcapnias
    dotNETZone.gr News
  •  27-06-2011, 15:55 66394 σε απάντηση της 66367

    Απ: EventHanlder Crash

    Σε ευχαριστώ πολύ, θα το παλέψω.

Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems