Implementasi Windows Normal di Delphi
Ringkasan di perpustakaan VCL Delphi, untuk kenyamanan penggunaan dan implementasi, aplikasi objek aplikasi membuat jendela tersembunyi untuk memproses respons pesan. Jendela inilah yang membuat program dikembangkan dengan VCL tampaknya agak cacat, seperti tidak dapat mengatur dan ubin secara normal dengan jendela lain. Melalui analisis mendalam dari VCL, artikel ini memberikan solusi yang dapat menyelesaikan masalah dengan hanya memodifikasi 3 baris kode ke file proyek aplikasi, tanpa perubahan apa pun pada metode pemrograman asli.
Kata kunci vcl, jendela normal, normalisasi
1 Pendahuluan
Aplikasi Windows yang ditulis dalam pustaka kelas VCL yang disediakan oleh Delphi memiliki fitur berbeda yang jelas berbeda dari jendela Windows standar - menu sistem jendela utama berbeda dari menu sistem di bilah tugas. Secara umum, menu sistem di jendela utama memiliki enam item menu, sedangkan menu Sistem Taskbar hanya memiliki tiga item menu. Dalam penggunaan aktual, kami menemukan bahwa program yang dikembangkan dengan VCL memiliki rasa malu berikut:
1) Tidak cukup indah. Ini pasti, jika tidak cocok dengan standar, secara alami akan tampak agak cacat.
2) Tidak ada efek animasi ketika jendela utama diminimalkan.
3) Jendela tidak dapat diatur dan ubin secara normal dengan jendela lain.
4) Menu Sistem Taskbar memiliki prioritas tertinggi. Di hadapan jendela modal, seluruh program masih dapat diminimalkan, bertentangan dengan desain jendela modal.
Masalah meminimalkan efek animasi di jendela utama telah diselesaikan oleh fungsi showwinnoanimate dalam bentuk.pas dalam versi setelah Delphi 5.0, tetapi masalah yang tersisa selalu ada. Meskipun ini tidak akan berdampak pada aplikasi dalam banyak kasus, memang tidak dapat diterima dalam beberapa situasi di mana efek profesional dikejar. Karena C ++ Builder dan Delphi menggunakan set pustaka kelas yang sama, masalah di atas juga ada di aplikasi Windows yang ditulis menggunakan C ++ Builder.
Saya telah membahas masalah ini dalam artikel sebelumnya (dapat ditemukan di rumah Forrest Gump), dan narasi pada waktu itu pada dasarnya tampaknya merupakan trik, dan saya menemukan metode itu secara kebetulan. Tugas artikel ini adalah untuk menganalisis perpustakaan kelas VCL untuk menjelaskan prinsip melakukan ini, dan kemudian memberikan metode yang hanya menggunakan 3 baris kode untuk sepenuhnya menyelesaikan masalah "jendela abnormal" ini di Delphi.
2 prinsip
2.1 Proses Pembuatan Aplikasi
Berikut adalah file proyek Delphi yang khas. Kami perhatikan bahwa ada referensi ke metode inisialisasi objek aplikasi dari awal, dan analisis kami dimulai dari sini:
Program Proyek1;
penggunaan
Bentuk,
Unit1 di 'unit1.pas' {form1};
{$ R *.res}
Mulai
Application.Initialize;
Application.createForm (tform1, form1);
Application.run;
akhir .
Jendela tersembunyi dibuat oleh objek aplikasi, jadi dari mana objek aplikasi berasal? Tekan dan tahan CTRL di jendela pengeditan kode Delphi dan klik aplikasi, Anda akan menemukan bahwa objek aplikasi adalah salah satu dari beberapa objek global yang ditentukan dalam unit Forms.pas. Ini tidak cukup, yang ingin kita ketahui adalah di mana objek aplikasi dibuat, karena instance dari kelas tapplikasi harus berhasil dibuat sebelum kita dapat merujuknya.
Pikirkan tentang hal ini, apakah ada kode yang akan dieksekusi sebelum aplikasi.Initialize? Ngomong -ngomong, itu adalah kode di segmen kode inisialisasi. Setelah dengan hati -hati men -debug kode sumber VCL, Anda dapat mengetahui bahwa banyak unit di VCL memiliki segmen kode inisialisasi. Semua tindakan inisialisasi.
Mencari di direktori kode sumber VCL dengan kata kunci "tapplication.create", kami menemukan kode untuk membuat objek aplikasi di unit controls.pas. Dalam segmen kode inisialisasi dari unit controls.pas, ada panggilan untuk prosedur initcontrols, dan implementasi initcontrols adalah sebagai berikut:
Kontrol unit ;
...
Inisialisasi
...
InitControls;
Prosedur InitControls;
Mulai
...
Mouse: = tmouse.create;
Layar: = tscreen.create ( nil );
Aplikasi: = tapplication.create ( nil );
...
akhir ;
OK, pada titik ini analisis kami telah menyelesaikan langkah pertama, karena untuk menyelesaikan masalah jendela yang tidak normal, kami harus melakukan satu hal sebelum menginisialisasi objek aplikasi, sehingga sangat penting untuk memahami proses inisialisasi aplikasi.
2.2 variabel islibrary
Variabel islibrary adalah salah satu variabel bendera global yang ditentukan dalam unit System.pas. Jika nilai islibrary benar, itu berarti bahwa modul program adalah pustaka tautan dinamis, jika tidak itu adalah program yang dapat dieksekusi. Beberapa proses dalam perpustakaan kelas VCL menyelesaikan tindakan yang berbeda berdasarkan nilai yang berbeda dari variabel flag ini. Artinya, variabel ini memainkan peran kunci dalam memecahkan masalah jendela abnormal Delphi.
Seperti yang disebutkan sebelumnya, untuk kenyamanan, jendela yang tidak terlihat dibuat ketika objek aplikasi diinisialisasi (yaitu, jendela dengan "tapplikasi" seperti nama kelas yang terlihat dengan alat -alat seperti Spy ++), tetapi juga karena hal ini tidak terlihat seperti yang dibuat oleh jendela ini yang tidak terlihat oleh jendela ini Program yang dikembangkan dengan Delphi menunjukkan banyak kelainan. Oke, jika kita dapat menghapus jendela yang tidak terlihat ini (dan menghapus menu Sistem Taskbar secara bersamaan) dan menggantinya dengan jendela utama aplikasi kita, bukankah semua masalah diselesaikan?
Sederhana untuk dikatakan, tetapi apakah memerlukan operasi besar untuk mengimplementasikan kode sumber VCL? Bukankah itu sedikit menempatkan kereta di depan kuda? Tentu saja jawabannya adalah tidak, jika tidak artikel ini tidak akan tersedia. Yang ingin saya katakan di sini adalah bahwa dalam analisis berikutnya, kita akan melihat bahwa apa yang disebut "cara pemrograman terletak pada satu pikiran", praktik penanaman willow yang tidak disengaja dalam desain tapplikasi sebenarnya meninggalkan kita dengan solusi untuk masalah ini Antarmuka. Jika Anda tidak melakukan analisis kode sumber, Anda mungkin harus berputar -putar, tetapi sebenarnya kita akan melihat bahwa desain jenius membuat kita tidak lebih atau kurang, tepat.
Buka konstruktor Create dari kelas tapplikasi dan kami akan menemukan baris kode seperti itu.
konstruktor tapplikasi.create (Aowner: tComponent);
Mulai
...
Jika tidak, islibrary maka createHandle;
...
akhir ;
Apa yang dikatakan di sini adalah bahwa jika modul program bukan perpustakaan tautan dinamis, maka jalankan createHandle, dan pekerjaan yang dilakukan oleh createHandle adalah sebagai berikut dalam bantuan: "Jika tidak ada jendela aplikasi, buat program aplikasi", di sini "" jendela "adalah jendela tak terlihat yang disebutkan di atas, yang merupakan pelakunya. Di kelas tapplikasi, variabel fhandle digunakan untuk menyimpan pegangan jendelanya. Ini untuk menyelesaikan tindakan yang berbeda sesuai dengan nilai islibrary, karena di pustaka tautan dinamis, loop pesan umumnya tidak diperlukan, tetapi untuk menggunakan objek aplikasi untuk mengembangkan pustaka tautan dinamis dengan VCL, jadi di sini adalah desainnya. Oke, kita hanya perlu menipu objek aplikasi, menetapkan islibrary ke true sebelum dibuat, dan memfilter eksekusi CreateHandle dan menghapus jendela yang menjengkelkan ini.
Kode yang ditugaskan ke islibrary harus ditempatkan di segmen kode inisialisasi dari unit tertentu. Objek aplikasi dibuat, dalam file proyek, kita harus menempatkan unit yang berisi kode penugasan sebelum unit formulir, sebagai berikut (dengan asumsi bahwa unit dinamai unitdllexe.pas):
templat program ;
penggunaan
Unitdllexe di 'unitdllexe.pas',
Bentuk,
FormMain di 'FormMain.pas' {MainForm},
...
Daftar kode unitdllexe.pas adalah sebagai berikut:
unit unitdllexe;
antarmuka
Pelaksanaan
Inisialisasi
Islibrary: = true;
// Beri tahu objek Applciation bahwa ini adalah pustaka tautan dinamis dan tidak perlu membuat jendela tersembunyi.
akhir .
Oke, kompilasi dan jalankan. windows. Tetapi masalahnya adalah bahwa jendela tidak dapat diminimalkan. Apa yang terjadi? Ini masih cara lama, ikuti.
2.3 Minimalisasi Jendela Utama
Minimalisasi milik perintah sistem, dan pada akhirnya, itu harus disebut fungsi API DEFWindowProc untuk meminimalkan jendela, jadi kami menemukan fungsi WMSYSCOMMAND dalam tcustomform yang menanggapi pesan WM_SYSSCOMMAND tanpa kesulitan apa pun, yang dengan jelas menulis untuk mengarahkan kembali pesan yang diminimalkan ke aplikasi aplikasi yang diminimalkan ke aplikasi yang diminimalkan ke aplikasi yang diminimalkan .Wndproc untuk ditangani:
Prosedur tcustomform.wmsysCommand (pesan var : twmsyscommand);
Mulai
dengan pesan lakukan
Mulai
if (cmdtype dan $ fff0 = sc_minimize) dan (application.mainform = self) lalu
Application.wndproc (tmessage (pesan))
...
akhir ;
akhir ;
Dalam application.wndProc, metode minimalkan aplikasi dipanggil sebagai tanggapan terhadap pesan yang diminimalkan, sehingga inti masalah harus dalam proses minimalkan.
prosedur tapplication.wndproc (pesan var : tmessage);
...
Mulai
...
dengan pesan lakukan
msg kasus
WM_SYSCOMMANT:
case wparam dan $ fff0 dari
Sc_minimize: Minimalkan;
Sc_restore: kembalikan;
kalau tidak
Bawaan;
...
akhir ;
Akhirnya, temukan tapplication.membunyikan dan Anda akan memahami semuanya. Panggilan ke fungsi DefWindowProc di sini tidak menghasilkan efek apa pun, mengapa? Karena kami menipu objek aplikasi sebelumnya, memfilter panggilan CreateHandle dan tidak membuat jendela yang diperlukan untuk menanggapi pesan objek aplikasi, pegangan fhandle adalah 0, dan panggilan tentu saja tidak berhasil. Jika Anda dapat mengarahkan Fhandle ke jendela aplikasi utama kami, itu akan menyelesaikan masalah.
Prosedur tapplikasi.minimize;
Mulai
...
DEFWINDOWPROC (fhandle, wm_syscommand, sc_minimize, 0);
// nilai fhandle di sini adalah 0
...
akhir ;
3 Implementasi
Desain jenius Borland yang tidak disengaja sekali lagi memungkinkan kami untuk menyelesaikan masalah. Dari analisis sebelumnya, kita tahu bahwa di pustaka tautan dinamis yang dikembangkan dengan VCL, tidak ada jendela tersembunyi untuk menerima pesan Windows (CreateHandle tidak mengeksekusi), tetapi di pustaka tautan dinamis, jika Anda ingin menampilkan jendela, Anda perlu jendela induk. Bagaimana cara menyelesaikan masalah ini? Desainer VCL merancang variabel fhandle yang memegang pegangan jendela yang tidak terlihat sebagai writable, sehingga kita sebenarnya dapat dengan mudah menetapkan nilai untuk Fhandle untuk menyediakan jendela induk untuk jendela anak yang perlu ditampilkan. Misalnya, dalam plug-in pustaka tautan dinamis untuk menampilkan formulir, kami biasanya melewati pegangan objek aplikasi melalui fungsi pustaka tautan dinamis di file modul utama yang dapat dieksekusi dan menetapkannya ke application.handle dari dinamis Link Library dalam file yang dapat dieksekusi modul utama dan tetapkan ke Application.handle dari pustaka tautan dinamis di aplikasi.
Prosedur SetApplicationHandle (MainAppwnd: HWND)
Mulai
Application.Handle: = MainAppWnd;
akhir ;
Oke, karena aplikasi. Penanganan sebenarnya hanyalah pegangan jendela yang digunakan secara internal untuk menanggapi pesan, dan jendela yang tidak terlihat yang seharusnya dibuat telah dihapus oleh kami, kami hanya perlu memberikan pegangan jendela untuk menggantikannya tidak Cukup untuk menyembunyikan pegangan jendela yang semula tidak perlu? Di mana saya dapat menemukan jendela seperti itu? Jendela utama aplikasi adalah pilihan terbaik, sehingga kode berikut tersedia.
templat program ;
penggunaan
Unitdllexe di 'unitdllexe.pas',
Bentuk,
FormMain di 'formmain.pas' {MainForm};
{$ R *.res}
Mulai
Application.Initialize;
Application.createForm (tFormMain, formmain);
Application.Handle: = FormMain.Handle;
Application.run;
akhir .
Jadi, semua masalah terpecahkan. Anda tidak perlu melakukan modifikasi apa pun pada kode sumber VCL, dan Anda tidak perlu melakukan modifikasi apa pun pada program asli. dari tiga baris kode untuk membuat jendela aplikasi Anda persis sama normalnya dengan jendela jendela standar mana pun.
1) Bilah tugas dan bilah judul jendela memiliki menu sistem yang konsisten.
2) Ada efek animasi ketika jendela utama diminimalkan.
3) Jendela dapat diatur dan ubin secara normal dengan jendela lain.
4) Ketika ada jendela modal, itu tidak dapat beroperasi di jendela induknya.
Kode implementasi di atas digunakan di semua versi Delphi.