Προγραμματισμός

Συγχώνευση Java και Win32: Ένας νέος τρόπος για την ανάπτυξη εφαρμογών Windows

Τα μέσα ενημέρωσης έχουν εστιάσει την προσοχή τους σε ορισμένες συγχωνεύσεις τις τελευταίες εβδομάδες. Τράπεζες, αυτοκινητοβιομηχανίες και αλυσίδες λιανικής έχουν ανακοινώσει ότι συγχωνεύονται. Μπορείτε να φανταστείτε το σοκ εάν η Sun Microsystems και η Microsoft αποφασίσουν ποτέ να συγχωνευτούν; Λοιπόν, δεν νομίζω ότι πρέπει να κρατάμε την ανάσα Πιστεύω, ωστόσο, ότι η Sun και η Microsoft θα μπορούσαν να μάθουν ένα ή δύο πράγματα μεταξύ τους. Μετά από όλα, και οι δύο εταιρείες έχουν αναπτύξει καλά προϊόντα - συγκεκριμένα Java και Win32. Κατά τη γνώμη μου, η καμπύλη εκμάθησης Java είναι πολύ μικρότερη από την καμπύλη εκμάθησης C ++. Ταυτόχρονα, το Win32 είναι ένας σημαντικός λόγος για τον οποίο η Microsoft διαθέτει Windows 95 / NT σε μερικά εκατομμύρια υπολογιστές. Φαίνεται φυσικό να συγχωνεύσουμε Java και Win32 για να δώσουμε στους προγραμματιστές το πλεονέκτημα που χρειάζονται για να δημιουργήσουν καλύτερες εφαρμογές Windows σε μικρότερο χρονικό διάστημα. Αυτό είναι το επίκεντρο αυτού του άρθρου.

Στην αρχή...

Οι πρώτες εφαρμογές των Windows γράφτηκαν στη γλώσσα Γ. Ενώ το C ήταν εντάξει για μικρές εφαρμογές, οι προγραμματιστές δυσκολεύτηκαν να χρησιμοποιήσουν αυτήν τη γλώσσα για να οργανώσουν μεγαλύτερες εφαρμογές. Το πρόβλημα επικεντρώθηκε γύρω από το μοντέλο ανταλλαγής μηνυμάτων των Windows και το γεγονός ότι το C είναι μια δομημένη και όχι μια αντικειμενική γλώσσα. Οι παραδοσιακές εφαρμογές που χρησιμοποιούν το C θα δημιουργήσουν ένα κύριο παράθυρο και θα εκχωρήσουν μια συνάρτηση επανάκλησης (γνωστή ως διαδικασία παραθύρου) σε αυτό το παράθυρο. Κάθε φορά που συνέβαινε κάτι σε αυτό το παράθυρο, τα Windows πυροδοτούσαν ένα μήνυμα στο παράθυρο καλώντας τη διαδικασία του παραθύρου. Η διαδικασία παραθύρου θα αποκρίνονταν πρώτα αναγνωρίζοντας το μήνυμα μέσω μιας τεράστιας δήλωσης περίπτωσης και στη συνέχεια θα επεξεργαζόταν το μήνυμα. Όπως συμβαίνει συχνά, η κατάσταση θα πρέπει να αποθηκευτεί μέσω τοπικών στατικών μεταβλητών ή καθολικών μεταβλητών. Μια μεγάλη εφαρμογή θα μπορούσε να οδηγήσει σε πολλές τέτοιες μεταβλητές. Αυτό το παράδειγμα λειτούργησε καλά για μικρότερες εφαρμογές, αλλά αποδείχθηκε επιζήμιο για μεγαλύτερες εφαρμογές. Κάτι έπρεπε να γίνει.

Η γλώσσα C εξελίχθηκε από μια δομημένη γλώσσα σε μια αντικειμενοστρεφή γλώσσα - μια γλώσσα που ονομάζεται C ++. Το ωραίο πράγμα για μια αντικειμενική γλώσσα είναι ότι δίνει στους προγραμματιστές τη δυνατότητα να μοντελοποιούν οντότητες πραγματικού κόσμου με πιο φυσικό τρόπο χρησιμοποιώντας αντικείμενα.

Πριν από λίγα χρόνια, η Microsoft κυκλοφόρησε ένα εργαλείο για προγραμματιστές που ήθελαν να δημιουργήσουν εφαρμογές Windows χρησιμοποιώντας το C ++. Αυτό το προϊόν έγινε γνωστό ως Visual C ++. Ένα από τα χαρακτηριστικά που παρουσιάστηκαν με το Visual C ++ ήταν ένα πλαίσιο εφαρμογής γνωστό ως Microsoft Foundation Classes (MFC). Το πλαίσιο MFC είναι μια συλλογή από τάξεις C ++, γραμμένες και δοκιμασμένες από τους προγραμματιστές της Microsoft, οι οποίες εφαρμόζουν πολλές βασικές λειτουργίες των Windows. Πολλές έννοιες λογισμικού - από γραμμές εργαλείων και γραμμές κατάστασης έως ένα μοντέλο προβολής εγγράφων που βασίζεται στην αρχιτεκτονική Model-View-Controller - έχουν εφαρμοστεί στο MFC. Η ιδέα πίσω από το MFC είναι να εξοικονομήσετε χρόνο κατά την ανάπτυξη χρησιμοποιώντας τον κώδικα MFC για το μεγαλύτερο μέρος της εφαρμογής και στη συνέχεια να επεκτείνετε το MFC για να παρέχει τις μοναδικές δυνατότητες αυτής της εφαρμογής - μέσω των θεμελιωδών αντικειμενοστρεφών εννοιών της ενθυλάκωσης, της κληρονομιάς και του πολυμορφισμού.

Ωστόσο, η ανάπτυξη λογισμικού με MFC δεν είναι εύκολη υπόθεση. Προκειμένου να γράψουν τις σημερινές εφαρμογές των Windows χρησιμοποιώντας C ++ και MFC, οι προγραμματιστές πρέπει να έχουν καλή κατανόηση των αντικειμενοστρεφών προγραμματιστικών εννοιών, της σύνταξης και των ιδιαιτεροτήτων C ++, των Windows API και του MFC.

Στην ιδανική περίπτωση, οι προγραμματιστές χρειάζονται μία γλώσσα και πλατφόρμα που τους επιτρέπει να γράφουν εφαρμογές μόνο μία φορά και στη συνέχεια να τις αναπτύσσουν παντού. Σε μια προσπάθεια να ανταποκριθεί σε αυτήν την ανάγκη, η Sun έχει εφαρμόσει ουδέτερες από την πλατφόρμα εκδόσεις πολλών Windows API, επιπλέον των API που είναι μοναδικά για την Java (όπως η Java Card). Τα API που ασχολούνται με τη διαχείριση αρχείων, αλληλογραφίας, βοήθειας, πολυμέσων και ασφάλειας έχουν αντίστοιχα στον κόσμο των Windows. Αυτό έχει ως αποτέλεσμα ένα σημαντικό όφελος για τους προγραμματιστές των Windows: Αντί να μάθουν πολλά Windows API μαζί με το C ++ και το MFC, οι προγραμματιστές μπορούν να επικεντρωθούν στην εκμάθηση της Java και των API της. Στη συνέχεια, μπορούν να χρησιμοποιήσουν την Java για να αναπτύξουν εφαρμογές Windows. Δείτε πώς.

Το API επίκλησης

Οι σχεδιαστές της Java βρήκαν έναν μηχανισμό για τη λήψη κώδικα Java για να μιλήσουν στον κώδικα C ++. Αυτός ο μηχανισμός χρησιμοποιεί μια συλλογή C ++ API γνωστών ως Java Native Interface (JNI). Πολλά από αυτά τα API έχουν συγκεντρωθεί και είναι συλλογικά γνωστά ως API επίκλησης.

Το API επίκλησης αποτελείται από διάφορες λειτουργίες JNI που επιτρέπουν στον προγραμματιστή να ενσωματώσει την εικονική μηχανή Java (JVM) σε μια αυθαίρετη εγγενή εφαρμογή. Με ενσωματωμένο JVM, η εγγενής εφαρμογή έχει πρόσβαση σε ολόκληρο το JVM πραγματοποιώντας κλήσεις JNI.

Το JVM δημιουργείται μέσω κλήσης στο JNI_CreateJavaVM () λειτουργία. Αυτή η συνάρτηση μεταφέρει έναν δείκτη στο a JDK1_1InitArgs δομή ως επιχείρημα. Αυτή η δομή παρέχει τις προεπιλεγμένες ρυθμίσεις για το JVM. Οι προεπιλογές μπορούν να παρακαμφθούν.

Για να λάβετε τις προεπιλεγμένες ρυθμίσεις, μια άλλη συνάρτηση JNI, JNI_GetDefaultJavaVMInitArgs (), πρέπει να κληθεί. Αυτή η λειτουργία μεταφέρει έναν δείκτη στο JDK1_1InitArgs δομή ως επιχείρημα. Μια τυπική ακολουθία κλήσεων εμφανίζεται στην ακόλουθη λίστα:

JDK1_1InitArgs vm_args; vm_args.version = 0x00010001; JNI_GetDefaultJavaVMInitArgs (& vm_args); 

Το πεδίο έκδοσης πρέπει να οριστεί πριν από την κλήση JNI_GetDefaultJavaVMInitArgs (). Αυτό το πεδίο διασφαλίζει ότι η σωστή JVM χρησιμοποιείται από την εφαρμογή. Η τιμή 0x00010001 κωδικοποιεί τον κύριο αριθμό έκδοσης του απαιτούμενου JVM στα υψηλά 16 bit και τον δευτερεύοντα αριθμό έκδοσης στα χαμηλά 16 bit. Η τιμή 0x00010001 σημαίνει ότι οποιοδήποτε JVM του οποίου ο αριθμός έκδοσης είναι 1.1.2 ή υψηλότερος θα ενσωματωθεί στην εφαρμογή.

Διάφορα ενδιαφέροντα πεδία περιλαμβάνουν το JDK1_1InitArgs δομή, αλλά το μόνο πεδίο που θα αναφέρουμε σε αυτό το άρθρο είναι το πεδίο που είναι γνωστό ως τάξη. Αυτό το πεδίο είναι σημαντικό επειδή λέει στο JVM πού βρίσκονται τα class.zip και τα αρχεία κλάσης εφαρμογών.

Μόλις το JDK1_1InitArgs η δομή έχει αρχικοποιηθεί, το JVM μπορεί να δημιουργηθεί μέσω μιας κλήσης προς JNI_CreateJavaVM (), όπως φαίνεται στην ακόλουθη λίστα:

JavaVM * jvm; JNIEnv * env; rc = JNI_CreateJavaVM (& jvm, & env, & vm_args); 

Σε αυτό το σημείο, το JNI λειτουργεί FindClass () και CallStaticVoidMethod () θα κληθεί να βρει την κατάλληλη αρχική τάξη Java και την κύρια μέθοδο εκκίνησης

Όταν το JVM δεν απαιτείται πλέον, καταστρέφεται από μια κλήση προς DestroyJavaVM (), όπως στην ακόλουθη λίστα.

jvm-> DestroyJavaVM () 

Λοιπόν, πώς μας επιτρέπει το API επίκλησης να δημιουργήσουμε εφαρμογές Win32 χρησιμοποιώντας Java; Το ακόλουθο παράδειγμα παρέχει μια απάντηση.

Ενα παράδειγμα

Αποφάσισα να δημιουργήσω μια εφαρμογή κονσόλας Win32 παρόμοια με το PKZIP, αλλά η εφαρμογή μου θα ήταν λίγο πιο απλή. Θα παρείχε μόνο τη δυνατότητα καταχώρισης όλων των αρχείων σε αρχείο zip και εξαγωγή αρχείων. Η εφαρμογή μου θα ξεκινήσει από τη γραμμή εντολών χρησιμοποιώντας την ακόλουθη σύνταξη:

c: \> zip [-x αρχείο] zip 

διά του οποίου είναι η σημαία εξαγωγής, αρχείο είναι το όνομα του αρχείου προς εξαγωγή και φερμουάρ είναι το όνομα του αρχείου με ή χωρίς επέκταση zip.

Η ακόλουθη λίστα εμφανίζει τον πηγαίο κώδικα C ++ zip.cpp. Αυτός ο κωδικός εφαρμόζει το ZIP εκτελέσιμο πρόγραμμα οδήγησης. Αυτό το πρόγραμμα οδήγησης φορτώνει το JVM, αναλύει τα ορίσματα της γραμμής εντολών, εντοπίζει το φερμουάρ αρχείο κλάσης, εντοπίζει την κύρια μέθοδο μέσα στο φερμουάρ αρχείο κλάσης, εκκινεί την κύρια μέθοδο (μεταβίβαση της λίστας ορισμάτων σε αυτήν τη μέθοδο) και εκφορτώνει το JVM.

// ================================================ === // zip.cpp // // ZIP Executable Driver // // Υποστηρίζει Java Virtual Machine (JVM) 1.1.2 ή υψηλότερη // ================= ================================== #include #include #include #include #define BUFSIZE 80 // == ============================================== // Χειριστής / / // Χειριστής ελέγχου κονσόλας // // Αγνοήστε όλες τις προσπάθειες τερματισμού της εφαρμογής. // // Επιχειρήματα: // // dwCtrlType - τύπος συμβάντος ελέγχου // // Return: // // TRUE (αγνοήστε το συμβάν) // ================== ============================== Χειριστής BOOL (DWORD dwCtrlType) {return TRUE; } // ======================================= // main // // Zip Σημείο εισόδου εκτελέσιμου προγράμματος οδήγησης // // Επιχειρήματα: // // argc - αριθμός ορισμάτων γραμμής εντολών // argv - πίνακας ορισμάτων γραμμής εντολών // // Return: // // 0 (επιτυχία) ή 1 (αποτυχία) / / ======================================= int main (int argc, char * argv [ ]) {int i; jint ret; JNIEnv * env; JavaVM * jvm; jclass clazz; jmethodID στα μέσα; JDK1_1InitArgs vm_args; char szBuffer [BUFSIZE], szClassPath [BUFSIZE * 2 + 15]; // Αποτρέψτε τον τερματισμό της εφαρμογής λόγω των πλήκτρων Ctrl-Break ή Ctrl-C, // κλικ στο κουμπί κλεισίματος παραθύρου, αποσύνδεση χρήστη ή τερματισμό του συστήματος. Χειριστής SetConsoleCtrlHandler ((PHANDLER_ROUTINE), TRUE); // Λάβετε προεπιλεγμένα ορίσματα αρχικοποίησης για JVM έκδοση 1.1.2 ή μεταγενέστερη. vm_args.version = 0x00010001; JNI_GetDefaultJavaVMInitArgs (& vm_args); // Ενημερώστε την JVM πού να βρείτε τα αρχεία κλάσης εφαρμογών και τις κατηγορίες.zip. GetPrivateProfileString ("CONFIG", "PATH", ".", SzBuffer, 80, "zip.ini"); wsprintf (szClassPath, "% s;% s \ class.zip;", szBuffer, szBuffer); vm_args.classpath = szClassPath; // Προσπάθεια δημιουργίας παρουσίας JVM. if ((ret = JNI_CreateJavaVM (& jvm, & env, & vm_args)) NewStringUTF (""); jobjectArray str_array = env-> NewObjectArray (argc - 1, env-> FindClass ("java / lang / String"), jstr); (i = 1; i NewStringUTF (argv [i])) == 0) {fprintf (stderr, "Out of memory \ n"); επιστροφή 1; } env-> SetObjectArrayElement (str_array, i - 1, jstr); } // Προσπάθεια εντοπισμού κλάσης zip. if ((clazz = env-> FindClass ("zip")) == 0) {fprintf (stderr, "Δεν μπορώ να εντοπίσω την κλάση zip. Έξοδος ... \ n"); επιστροφή 1; } // Προσπαθήστε να εντοπίσετε την κύρια μέθοδο zip class. if ((mid = env-> GetStaticMethodID (clazz, "main", "([Ljava / lang / String;) V")) == 0) {fprintf (stderr, "Δεν μπορώ να εντοπίσω την κύρια μέθοδο. Έξοδος. .. \ n "); επιστροφή 1; } // Εκκίνηση κύριας μεθόδου. env-> CallStaticVoidMethod (clazz, mid, str_array); // Καταστρέψτε την παρουσία JVM. jvm-> DestroyJavaVM (); επιστροφή 0; } 

Σημειώστε την κλήση στο Win32 GetPrivateProfileString () λειτουργία. Αυτή η συνάρτηση αναζητά ένα αρχείο που ονομάζεται zip.ini (που θα βρίσκεται στον κατάλογο των Windows - συνήθως c: \ windows κάτω από τα Windows 95 ή c: \ winnt στα Windows NT). Ο σκοπός αυτού του αρχείου είναι να κρατήσει τη διαδρομή όπου είναι εγκατεστημένη η εφαρμογή ZIP. Το JVM θα αναζητήσει σε αυτήν την τοποθεσία για αρχεία class.zip και κλάσης εφαρμογών (ανεξάρτητα από το πού καλείται η εφαρμογή ZIP).

Ένα άλλο στοιχείο που πρέπει να σημειωθεί είναι μια κλήση στο SetConsoleCtrlHandler () API Win32. Αυτό το API αποτρέπει το πάτημα των πλήκτρων Ctrl-C ή Ctrl-Break - εκτός από άλλα συμβάντα - από τη διακοπή της εφαρμογής πριν ολοκληρωθεί. Αυτό μπορεί ή όχι να είναι επιθυμητό, ​​ανάλογα με την εφαρμογή.

Η εφαρμογή ZIP είναι γραμμένη σε Java. Δίνει στους χρήστες τη δυνατότητα να βλέπουν τα περιεχόμενα των αρχείων αρχειοθέτησης zip, καθώς και τη δυνατότητα εξαγωγής μεμονωμένων αρχείων από αυτά τα αρχεία. Η ακόλουθη λίστα περιέχει τον πηγαίο κώδικα στο ZIP.