Обединяване на Java и Win32: нов начин за разработване на приложения за Windows

Новините медии насочиха вниманието си към редица сливания през последните седмици. Банки, автомобилни корпорации и търговски вериги обявиха, че се сливат. Можете ли да си представите шока, ако Sun Microsystems и Microsoft някога решат да се обединят? Е, не мисля, че трябва да затаим дъх. Мисля обаче, че Sun и Microsoft биха могли да научат нещо или две един от друг. В крайна сметка и двете компании са разработили добри продукти - а именно Java и Win32. Според мен кривата на обучение на Java е много по-къса от кривата на обучение C ++. В същото време Win32 е една от важните причини, поради които Microsoft има Windows 95 / NT, работещ на няколко милиона компютъра. Изглежда съвсем естествено да се обединят Java и Win32, за да се даде на разработчиците предимство, необходимо за създаване на по-добри приложения за Windows за по-кратки периоди от време. Това е фокусът на тази статия.

В началото...

Първите приложения за Windows са написани на езика C. Докато C беше добре за малки приложения, разработчиците се затрудниха да използват този език за организиране на по-големи приложения. Проблемът се концентрира около модела за съобщения на Windows и факта, че C е структуриран, а не обектно-ориентиран език. Традиционните приложения, използващи C, ще създадат главен прозорец и ще присвоят функция за обратно извикване (известна като процедура на прозорец) към този прозорец. Всеки път, когато нещо последствие се случи с този прозорец, Windows ще изстреля съобщение към прозореца, като извика процедурата на прозореца. Процедурата на прозореца ще отговори, като първо идентифицира съобщението чрез огромен оператор за превключване и след това обработи съобщението. Както често се случва, състоянието ще трябва да се запазва чрез локални статични променливи или глобални променливи. Голямо приложение може да доведе до много такива променливи. Тази парадигма работи добре за по-малки приложения, но се оказа вредна за по-големите приложения. Трябваше да се направи нещо.

Езикът C еволюира от структуриран език в обектно-ориентиран език - език, наречен C ++. Хубавото на обектно-ориентирания език е, че той дава на разработчиците способността да моделират обекти от реалния свят по по-естествен начин, като използват обекти.

Преди няколко години Microsoft пусна инструмент за разработчици, които искаха да създават приложения за Windows, използващи C ++. Този продукт стана известен като Visual C ++. Една от функциите, въведени с Visual C ++, беше рамка за приложения, известна като Microsoft Foundation Classes (MFC). Рамката MFC е колекция от класове C ++, написана и тествана от разработчиците на Microsoft, която реализира много основни функционалности на Windows. В MFC са внедрени много софтуерни концепции - от ленти с инструменти и ленти за състояние до модел на изглед на документ, базиран на архитектурата Model-View-Controller. Идеята на MFC е да спести време по време на разработката, като използва MFC код за по-голямата част от приложението и след това разширява MFC, за да осигури уникалните възможности на това приложение - чрез основните обектно-ориентирани концепции за капсулиране, наследяване,и полиморфизъм.

Разработването на софтуер с MFC обаче не е лесна задача. За да напишат днешните приложения за Windows, използващи C ++ и MFC, разработчиците трябва добре да разбират обектно-ориентираните концепции за програмиране, C ++ синтаксис и особености, API на Windows и MFC.

В идеалния случай разработчиците се нуждаят от един език и платформа, които им позволяват да пишат приложения само веднъж и след това да ги разполагат навсякъде. В опит да отговори на тази необходимост, Sun е внедрил неутрални за платформата версии на много приложни програмни интерфейси (API) на Windows в допълнение към уникалните за Java приложни програмни интерфейси (като Java Card). Приложните програмни интерфейси (API), занимаващи се с управление на файлове, поща, помощ, мултимедия и сигурност, имат аналози в света на Windows. Това води до една голяма полза за разработчиците на Windows: Вместо да изучават много приложни програмни интерфейси на Windows заедно със 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 ()функцията. Тази функция приема указател към JDK1_1InitArgsструктура като аргумент. Тази структура осигурява настройки по подразбиране за JVM. По подразбиране могат да бъдат заменени.

За да получите настройките по подразбиране JNI_GetDefaultJavaVMInitArgs (), трябва да се извика друга функция JNI . Тази функция приема указател към JDK1_1InitArgsструктурата като аргумент. Типична последователност на обажданията се появява в следния списък:

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

Полето за версия трябва да бъде зададено преди извикване JNI_GetDefaultJavaVMInitArgs (). Това поле гарантира, че приложението използва правилния JVM. Стойност 0x00010001 кодира основния номер на версията на необходимия JVM във високите 16 бита и второстепенния номер на версията в ниските 16 бита. Стойността 0x00010001 означава, че всеки JVM, чийто номер на версия е 1.1.2 или по-висок, ще бъде вграден в приложението.

Няколко интересни полета съдържат JDK1_1InitArgsструктурата, но единственото поле, което ще споменем в тази статия, е полето, известно като classpath. Това поле е важно, защото казва на JVM къде се намират класовете .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 

при което -xе флагът за извличане, fileе името на файла за извличане и zipе името на архива със или без zip разширение.

Следният списък показва изходния код на C ++ zip.cpp. Този код изпълнява ZIP изпълнимия драйвер. Този драйвер зарежда JVM, анализира аргументите от командния ред, локализира ZIPфайла на класа, локализира основния метод в рамките на ZIPфайла на класа, стартира основния метод (предава списъка с аргументи на този метод) и разтоварва JVM.

// ================================================== === // zip.cpp // // ZIP изпълним драйвер // // Поддържа Java Virtual Machine (JVM) 1.1.2 или по-нова версия // ================= ================================== #include #include #include #include #define BUFSIZE 80 // == ================================================ // Манипулатор / // Консолен манипулатор // // Игнорирайте всички опити за изключване на приложението. // // Аргументи: // // dwCtrlType - тип на събитието за управление // // Връщане: // // TRUE (игнориране на събитие) // ================== ============================== BOOL манипулатор (DWORD dwCtrlType) {връщане TRUE; } // ========================================= // основна // // Zip Изпълним драйвер за вход // // Аргументи: // // argc - брой аргументи на командния ред // argv - масив от аргументи на командния ред // // Връщане:// // 0 (успех) или 1 (неуспех) // ======================================= ==== int main (int argc, char * argv []) {int i; jint ret; JNIEnv * env; JavaVM * jvm; jclass clazz; jmethodID mid; 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 \\ класове.zip;", szBuffer, szBuffer); vm_args.classpath = szClassPath; // Опит за създаване на екземпляр на JVM. ако ((ret = JNI_CreateJavaVM (& jvm, & env, & vm_args)) NewStringUTF (" ") argc - 1, env-> FindClass ("java / lang / String"), jstr); for (i = 1; i NewStringUTF (argv [i])) == 0) {fprintf (stderr, "Няма памет \ n "); return 1;} env-> SetObjectArrayElement (str_array, i - 1, jstr);} // Опит за намиране на zip клас. if ((clazz = env-> FindClass (" zip ")) == 0) {fprintf (stderr, "Не мога да намеря zip класа. Излизане ... \ n"); връщане 1;} // Опит за намиране на основния метод на zip класа. if ((mid = env-> GetStaticMethodID (clazz, "main", "([Ljava / lang / String;) V")) == 0) {fprintf (stderr, "Can 'намерете основния метод. Излиза ... \ n "); return 1;} // Стартирайте основния метод. Env-> CallStaticVoidMethod (clazz, mid, str_array); // Унищожете екземпляра на JVM. Jvm-> DestroyJavaVM (); return 0;}

Обърнете внимание на повикването към функцията Win32 GetPrivateProfileString (). Тази функция търси файл, наречен zip.ini(който ще се намира в директорията на Windows - обикновено c: \ windows под Windows 95 или c: \ winnt под Windows NT). Целта на този файл е да задържи пътя, където е инсталирано ZIP приложението. JVM ще търси на това място файлове class.zip и класове на приложения (без значение откъде се извиква ZIP приложението).

Друг елемент, който трябва да се отбележи, е извикване на SetConsoleCtrlHandler ()Win32 API. Този API предотвратява натискането на клавиши Ctrl-C или Ctrl-Break - в допълнение към други събития - от спиране на приложението, преди да приключи. Това може или не може да бъде желателно, в зависимост от приложението.

Приложението ZIP е написано на Java. Той дава на потребителите възможност да преглеждат съдържанието на zip архивни файлове, както и възможността да извличат отделни файлове от тези архиви. Следният списък съдържа изходния код към ZIP.