1. Penunjuk fungsi
AddressOf mendapatkan penunjuk fungsi di dalam VB. Kita dapat meneruskan penunjuk fungsi ini ke API yang perlu memanggil kembali fungsi ini.
Namun, penerapan penunjuk fungsi di VB tidak seluas di C, karena dokumen VB hanya memperkenalkan cara meneruskan penunjuk fungsi ke API untuk mengimplementasikan panggilan balik, dan tidak menunjukkan banyak fungsi ajaib dari penunjuk fungsi, karena VB tidak menganjurkan Saat menggunakan pointer, tidak terkecuali pointer fungsi.
Pertama, mari kita klasifikasikan bagaimana penunjuk fungsi digunakan.
1. Panggilan balik. Ini adalah fungsi paling mendasar dan penting. Misalnya, inti dari teknologi derivasi subkelas yang diperkenalkan dalam dokumentasi VB adalah dua API: SetWindowLong dan CallWindowPROc.
Kita dapat menggunakan SetWindowLong API untuk mengganti penunjuk fungsi jendela asli dengan penunjuk fungsi kita sendiri, dan menyimpan penunjuk fungsi jendela asli. Dengan cara ini, pesan jendela dapat dikirim ke fungsi kita sendiri, dan kita dapat menggunakan CallWindowProc untuk memanggil penunjuk jendela yang disimpan sebelumnya kapan saja untuk memanggil fungsi jendela asli. Dengan cara ini, kita dapat menangani pesan terkait tanpa merusak fungsi jendela aslinya.
Kita harus memahami proses spesifiknya, dan dokumen VB juga menjelaskannya dengan sangat jelas. Yang perlu diperhatikan di sini adalah CallWindowProc API, kita akan melihat kegunaannya yang luar biasa nanti.
Di sini kita memanggil panggilan balik untuk mengizinkan "panggilan eksternal ke penunjuk fungsi internal".
2. Untuk penggunaan internal program. Misalnya, di C, kita bisa meneruskan penunjuk fungsi C sebagai parameter ke fungsi C yang memerlukan penunjuk fungsi, seperti fungsi pustaka C qsort yang akan dibahas nanti.
Dibutuhkan penunjuk fungsi tipe COMPARE untuk membandingkan ukuran dua variabel, sehingga fungsi pengurutan dapat memanggil penunjuk fungsi ini untuk membandingkan berbagai jenis variabel, sehingga qsort dapat mengurutkan array variabel dari jenis yang berbeda.
Sebut saja aplikasi ini "memanggil penunjuk fungsi internal dari dalam".
3. Memanggil fungsi eksternal
Anda mungkin bertanya, bukankah menggunakan API hanya memanggil fungsi eksternal? Ya, tapi terkadang kita masih perlu mendapatkan penunjuk fungsi eksternal secara langsung. Misalnya, memuat DLL secara dinamis melalui LoadLibrary, lalu mendapatkan penunjuk entri fungsi yang kita perlukan melalui GetProcAddress, dan kemudian memanggil fungsi eksternal melalui penunjuk fungsi ini. Teknologi memuat DLL secara dinamis ini memungkinkan kita memanggil fungsi eksternal dengan lebih fleksibel.
Kami menyebut metode ini "memanggil penunjuk fungsi eksternal dari dalam"
4. Tak perlu dikatakan lagi, kita juga dapat mengontrol "memanggil penunjuk fungsi eksternal dari luar". Tidak, misalnya, kita dapat memuat beberapa DLL dan meneruskan penunjuk fungsi di satu DLL ke fungsi di DLL lain.
Pembagian "internal" dan "eksternal" di atas semuanya relatif (DLL sebenarnya masih dalam proses). Klasifikasi ini akan membantu kita membahas masalah di masa depan. Harap ingat klasifikasi saya di atas, karena artikel mendatang juga akan Gunakan klasifikasi ini untuk menganalisis masalahnya.
Penggunaan fungsi pointer tidak lebih dari empat cara di atas. Namun dalam penggunaan sebenarnya itu fleksibel dan dapat diubah. Misalnya, pewarisan dan polimorfisme di C, dan antarmuka di COM merupakan aplikasi pintar dari tabel penunjuk fungsi yang disebut vTable. Menggunakan penunjuk fungsi dapat membuat pemrosesan program lebih efisien dan fleksibel.
Kecuali untuk metode pertama, dokumen VB tidak memperkenalkan metode lain, dan juga dengan jelas menyatakan bahwa penunjuk fungsi "Basic to Basic" tidak didukung (yaitu, metode kedua yang disebutkan di atas). keempat metode di atas dapat dicapai. Hari ini, mari kita lihat cara menerapkan metode kedua. Karena penerapannya relatif sederhana, mari kita mulai dengan yang sederhana. Adapun cara memanggil pointer fungsi eksternal di VB, dan bagaimana mewujudkan penerapan cerdas berbagai pointer fungsi dengan memproses tabel lompat penunjuk fungsi antarmuka vTable di VB, karena ini akan melibatkan prinsip internal COM, saya akan menguraikannya di artikel lain .
Faktanya, dokumentasi VB tidak salah. VB tidak mendukung penunjuk fungsi "Basic to Basic", tetapi kita dapat membuat cara memutar untuk mencapainya, yaitu pertama "Basic to API", dan kemudian menggunakan metode pertama. "eksternal Panggil penunjuk fungsi internal" untuk beralih dari "API ke BASIC", sehingga mencapai tujuan cara kedua dari "Basic ke Basic". Kita dapat menyebut teknologi ini "panggilan balik paksa", yang hanya tersedia di VB Aneh sekali teknologi.
Ini agak berbelit-belit, tapi pikirkan baik-baik tentang CallWindowProc dalam teknologi derivasi subkelas jendela. Kita dapat menggunakan CallWindowProc untuk memaksa sistem operasi eksternal memanggil penunjuk fungsi jendela asli yang disimpan penunjuk fungsi.
Haha, sudah saya katakan sebelumnya bahwa kita sebaiknya tidak banyak bicara tentang prinsip dan lebih banyak bicara tentang jurus. Sekarang mari kita mulai mempelajari jurusnya!
Pertimbangkan bahwa kami menerapkan qsort di VB yang mendukung perbandingan multi-kata kunci seperti C. Kode sumber selengkapnya dapat ditemukan pada kode pendukung artikel ini. Hanya kode yang terkait dengan aplikasi penunjuk fungsi yang diberikan di sini.
Mari kita lihat pernyataan qsort terakhir kita.
ArrayPtr di atas adalah penunjuk ke elemen pertama array yang perlu diurutkan, nCount adalah jumlah elemen dalam array, nElemSize adalah ukuran setiap elemen, dan pfnCompare adalah penunjuk fungsi perbandingan kita. Deklarasi ini sangat mirip dengan qsort di fungsi perpustakaan C.
Seperti C, kita bisa meneruskan penunjuk fungsi Basic ke fungsi qsort Basic.
Cara menggunakannya:
Sobat cerdas, sudahkah kalian melihat misterinya di sini? Sebagai ujian, bisakah Anda memberi saya cara menggunakan penunjuk fungsi di qsort? Misalnya, sekarang kita perlu membandingkan ukuran elemen ke-i dan elemen ke-j dari array dengan memanggil penunjuk fungsi.
Ya, tentu saja Anda harus menggunakan API Bandingkan yang dideklarasikan sebelumnya (sebenarnya CallWindowProc) untuk melakukan panggilan balik paksa.
Implementasi spesifiknya adalah sebagai berikut:
Gerakannya diperkenalkan, apakah Anda mengerti? Izinkan saya menjelaskan secara singkat arti Bandingkan di atas. Ini memanfaatkan CallWindowProc API dengan sangat cerdas. API ini memerlukan lima parameter. Parameter pertama adalah penunjuk fungsi biasa. API ini dapat segera memanggil kembali penunjuk fungsi dan meneruskan empat parameter tipe panjang terakhir dari API ini ke fungsi yang ditunjuk oleh penunjuk fungsi. Inilah sebabnya fungsi perbandingan kita harus memiliki empat parameter, karena CallWindowProc API mengharuskan penunjuk fungsi yang diteruskan ke dalamnya harus sesuai dengan prototipe fungsi WndProc. Prototipe WndProc adalah sebagai berikut:
LRESULT, HWND, UINT, WPARAM, dan LPARAM di atas semuanya bisa sesuai dengan tipe Long di VB. Ini bagus sekali, karena tipe Long bisa digunakan sebagai pointer!
Mari kita lihat alur kerjanya lagi. Saat kita memanggil qsort menggunakan AddressOfCompareSalaryName sebagai parameter penunjuk fungsi, parameter formal pfnCompare dari qsort ditetapkan sebagai penunjuk fungsi dari parameter aktual CompareSalaryName. Saat ini, memanggil Bandingkan untuk memaksa panggilan balik ke pfnCompare sama dengan memanggil pernyataan VB berikut:
Bukankah ini akan menyebabkan kesalahan ketidakcocokan tipe parameter? Bukankah dua parameter pertama CompareSalaryName bertipe TEmployee? Memang benar, panggilan seperti itu tidak mungkin dilakukan di VB, karena pemeriksaan tipe VB tidak akan mengizinkan panggilan seperti itu. Namun, panggilan ini sebenarnya adalah panggilan balik yang dibuat oleh API, dan VB tidak mungkin memeriksa apakah tipe parameter fungsi panggilan balik API adalah tipe numerik Panjang biasa atau penunjuk struktur, sehingga dapat juga dikatakan bahwa kita punya melewati kontrol parameter fungsi VB. Untuk pemeriksaan tipe, kita dapat mendeklarasikan parameter Long ini sebagai penunjuk tipe apa pun. Oleh karena itu, kita harus menggunakan teknik ini dengan hati-hati. Misalnya, parameter "ArrayPtr (i-1)*nElemSize" yang pada akhirnya akan diteruskan ke fungsi CompareSalaryName di atas hanyalah sebuah alamat alamat diperlakukan sebagai penunjuk tipe TEmployee. Jika tidak sengaja digunakan sebagai "ArrayPtr i*nElemSize", maka ketika i adalah elemen terakhir, kita akan menyebabkan kesalahan akses memori, jadi kita harus memperhatikan masalah batas seperti ketika menangani pointer di C.
Penerapan penunjuk fungsi yang cerdas sudah dapat dilihat di sini, tetapi metode yang diperkenalkan di sini masih memiliki keterbatasan besar. Fungsi kita harus memiliki empat parameter. Pendekatan yang lebih bersih adalah dengan menulis DLL di VC atau Delphi dan membuat API yang lebih sesuai untuk mengimplementasikan fungsi mirip dengan CallWindowProc. Saya telah menelusuri implementasi internal CallWindowProc. Ia melakukan banyak pekerjaan terkait dengan pesan jendela, yang mubazir dalam aplikasi kita. Faktanya, untuk mengimplementasikan API panggilan balik paksa, Anda hanya perlu memasukkan beberapa parameter terakhir ke dalam tumpukan dan kemudian memanggil parameter pertama, yang hanya merupakan beberapa instruksi perakitan.
Justru karena keterbatasan CallWindowProc kita tidak dapat menggunakannya untuk memanggil penunjuk fungsi eksternal untuk mengimplementasikan metode pemanggilan penunjuk fungsi ketiga yang disebutkan di atas. Untuk mengimplementasikan metode ketiga, Master MattCurland menyediakan metode HACK seperti mimpi buruk. Kita perlu membuat antarmuka IUnknown di VB, dan menambahkan entri baru setelah tiga entri asli dari vTable antarmuka IUnknown entri baru Masukkan kode mesin ke dalamnya. Kode mesin ini harus menangani penunjuk ini sebelum akhirnya memanggil penunjuk fungsi yang kami berikan. Saya akan kembali ke metode ini ketika kita mendalami internal COM.
Selain itu, algoritma pengurutan adalah masalah opini. Awalnya saya ingin memberikan algoritma paling serbaguna dengan kinerja terbaik dalam artikel ini. Metode penyortiran cepat yang diimplementasikan menggunakan berbagai teknologi penunjuk yang disediakan dalam artikel ini seharusnya jauh lebih cepat dan menggunakan lebih sedikit memori dibandingkan menggunakan teknologi objek untuk mengimplementasikan fungsi yang sama. Namun algoritma quick sort yang sudah saya optimalkan ini masih belum sebaik ShellSort karena ShellSort mudah diimplementasikan. Secara teoritis dari algoritma, qsort seharusnya memiliki kinerja rata-rata yang lebih baik daripada ShellSort, tetapi hal ini belum tentu terjadi di VB (Anda dapat melihat kode pendukung artikel ini, yang juga menyediakan kode pendukung kolom VBPJ, ShellSort, yaitu sangat bagus, dan ide artikel ini diambil dari This ShellSort).
Namun, perlu dicatat bahwa Quick Sort dan ShellSort di sini dapat ditingkatkan secara signifikan, karena implementasinya memerlukan penggunaan CopyMemroy yang ekstensif untuk menyalin data (ini adalah salah satu kelemahan menggunakan pointer di VB). Sebenarnya kita punya cara yang lebih baik, yaitu dengan meretas struktur array VB, yaitu SafeArray dalam otomatisasi COM. Kita bisa memasukkan pointer setiap elemen array di SafeArray ke dalam array panjang sekaligus untuk menukar elemen dalam array Panjang untuk mencapai tujuan pertukaran pointer elemen array SafeArray secara real time. Data tidak dipindahkan, hanya pointer yang dipindahkan.
->