Κυριακή, 30 Ιουλίου 2017

Αναθεώρηση 23 (Έκδοση 8.9)

Διόρθωσα ένα πρόβλημα που μπορούσε να προκύψει, αν διορθώναμε κείμενο στη κονσόλα της Μ2000 ενώ είχαμε ανοικτή μια φόρμα χρήστη. Υπήρχε πρόβλημα με το μηχανισμό για να παίρνει ο διορθωτής το γεγονός από το ροδελάκι του ποντικιού. O μηχανισμός για να πάρει το γεγονός χρειάζεται επειδή δεν το δίνει η Visual Basic 6 στις φόρμες της. Ουσιαστικά οι φόρμες της VB6 είναι αντικείμενα πάνω στα αντικείμενα παραθύρων των Windows (παρόμοιος τρόπο δουλεύει και η Μ2000, όπου οι φόρμες χρήστη είναι αντικείμενα πάνω από τις φόρμες της VB6).
Ο μηχανισμός κάνει Hook (αγκιστρώνει) μια συνάρτηση που ελέγχει τα μηνύματα γεγονότων όπως παράγονται από το σύστημα των Windows. Όταν δεν το χρειαζόμαστε τότε γίνεται Unhook, δηλαδή βγαίνει εκτός. Για να κατανοήσει κανείς αυτό το αγκίστρωμα, αρκεί να σκεφτεί ότι κάθε παράθυρο δηλώνει μια διεύθυνση μιας συνάρτησης που εξυπηρετεί γεγονότα, την λεγόμενη και WindowProc (η διαδικασία παραθύρων). Για να γίνει subclassing, πρέπει να πάρουμε αυτή τη διεύθυνση και να την φυλάξουμε, και αυτό γίνεται γιατί γνωρίζουμε μια ιδιότητα των παραθύρων, το hWnd, ή window handler, τον χειριστή του παραθύρου, που είναι ένας αριθμός. Κάθε παράθυρο, ακόμα και στοιχείο στο παράθυρο που είναι αντικείμενο Window, έχει τον δικό του χειριστή, που ορίζεται από το σύστημα των Windows. Όπως όταν ανοίγουμε ένα αρχείο μας δίνει το σύστημα ένα χειριστή αρχείου (file handler) έτσι είναι και ο χειριστής παραθύρου.  Με αυτόν τον χειριστή βρίσκουμε πολλά πράγματα για το παράθυρο, και ένα από αυτά είναι η διεύθυνση της συνάρτησης (ή ρουτίνας αν θέλουμε να την πούμε και έτσι), που δέχεται τα μηνύματα από τα γεγονότα και οφείλει να τα αποδεσμεύσει, είτε τα ικοανοποιήσει είτε όχι, διαφορετικά το σύστημα βγάζει συμπέρασμα, μετά από κάποιο χρόνο, ότι η εφαρμογή έχει κρεμάσει! Όταν χρησιμοποιούνται χειριστές (αυτοί οι αριθμοί) σημαίνει ότι τα δεδομένα είναι εκτός διαδικασίας, ή process, δηλαδή ανήκουν κάπου αλλού. Πράγματι τα δεδομένα για τα παράθυρα ανήκουν στον Window Manager, στο πρόγραμμα που λειτουργεί τα παράθυρα και τα στοιχεία τους στο λειτουργικό. Υπάρχει περιορισμός για τα πόσα παράθυρα μπορούμε να ανοίξουμε. Μπορούμε να δούμε ένα πρόγραμμα πόσους handlers χρησιμοποιεί μια δεδομένη στιγμή από τον Windows Task Manager, στη καρτέλα Processes, αν επιλέξουμε να μας δείχνει την στήλη Handlers. H M2000 χρησιμοποιεί περίπου 240, το Notepad περίπου 78, ενώ ο explorer περνάει τους 1000. Βέβαια το νούμερο δεν μας δείχνει μόνο τους handlers του Window Manager, αλλά και όλους τους άλλους, για αντικείμενα των windows που δεν είναι απαραίτητα στοιχεία των παραθύρων.

Για να γίνει λοιπόν το subclassing πρέπει να ενημερώσουμε τον Window Manager ότι αλλάζει η ρουτίνα εξυπηρέτησης, αλλά προσοχή εδώ, η δική μας ρουτίνα πρέπει στο τέλος να καλεί την από πριν καθορισμένη! Όταν γίνεται Unhook τότε απλά ενημερώνουμε τον Windows Manager δίνοντας την καθορισμένη ως την μόνη ρουτίνα εξυπηρέτησης.

Παρακάτω είναι το πρόγραμμα που έβγαζε κόλλημα (hang), γιατί όταν ξεκίναγε ο διορθωτής στη κονσόλα (είχε γραφτεί πριν υπάρξουν φόρμες χρήστη στη Μ2000), με τρόπο κλείδωνε την φόρμα (ενώ δεν ήταν κλειδωμένη, μια σημαία (flag) εσωτερικά έκοβε την πρόσβαση στη φόρμα), με σκοπό να κάνει το στοιχείο "διορθωτής" να είναι το μόνο με το οποίο δουλεύουμε. Νήματα μπορούσαν να τρέξουν πίσω, καθώς επίσης μπορούσε το παράθυρο επιλογών (το βλέπουμε ως αναπτυσσόμενη λίστα επιλογών ή context menu), το οποίο όμως έχει ξεχωριστή ρουντίνα hook, για τη δική του μπάρα ολίσθησης). Όταν φτιάχτηκαν οι φόρμες χρήστη έπρεπε να βρεθεί ένας τρόπος, ώστε οποιοδήποτε στοιχείο πάνω στη φόρμα να παίρνει το γεγονός αλλαγής της ροδέλας του ποντικιού, χωρίς να χρειάζεται ξεχωριστή ρουτίνα hook. Το πρόβλημα με τις ρουτίνες αυτές είναι ότι απαιτούν σταθερή διεύθυνση μνήμης, πριν ακόμα εκτελεστεί το περιβάλλον της Μ2000, έτσι πώς θα ήταν δυνατόν να έχουμε οποιοδήποτε αριθμό φορμών και στοιχείων και να έχουμε μια Hook ευκολία; Το πρόβλημα λύθηκε με την ιδέα ότι η συνάρτηση αυτή θα δίνεται και θα παίρεται από το κάθε ενδιαφερόμενο στοιχείο. (και η φόρμα Ρυθμίσεις λειτουργεί έτσι, για όλα τα στοιχεία της). Όμως δεν είχε ξεκαθαριστεί το πώς θα γίνονταν στο διορθωτή κειμένου της κονσόλας (είναι διαφορετικό αντικείμενο, πάνω σε ένα κοινό αντικείμενο usercontrol της VB6, σε σχέση με το στοιχείο TextBox, ή Κείμενο), Τώρα λοιπόν ξεκαθαρίστηκε (Αφού επισημάνθηκε το πρόβλημα).




declare form1 form
declare inp1 TextBox form form1

method form1, "show"
show
document a$
\\ now open in console the editor
\\ when open move form1
\\ before revision 23 m2000 environment hang
\\ because edit.doc editor subclassing mouse enent
\\ we can't use subclassing in the mouse event while we leave console form
\\ can't work so now is fixed by unhooking subclassing when form deactivated.
edit.doc a$
print "ok"
declare form1 Nothing