Senin, 23 Januari 2012

File DLL Visual Basic

Membuat Sendiri File DLL (Dynamic Link Library)

Membuat component DLL in-process di Visual Basic tidaklah terlalu berbeda dari membuat component out-of-process, jadi secara umum teknik yang dideskripsikan di bagian lain yang berjudul "Creating an ActiveX EXE Server" juga cocok untuk "ActiveX DLL Components". Dalam bagian ini kita akan memfokuskan pada beberapa perbedaan di antara dua tipe component tersebut.
Component In-Process di IDE Visual Basic
Component In-Process dapat dibuat dari kotak dialog "Project Properties" dengan mengganti sebuah class yang berdasarkan pada project "Standard EXE" menjadi sebuah project bertipe "ActiveX DLL", seperti yang Anda lakukan pada component Out-of-Process. Alternatif lainnya, Anda dapat membuat sebuah project ActiveX DLL dari kotak dialog "Project Gallery" yang muncul ketika Anda membangkitkan perintah "New Project" dari menu "File".
Perbedaan utama antara membuat component Out-of-Process dan In-Process adalah bahwa yang terakhir disebut dapat dibuat dalam IDE yang sama dan bertindak sebagai client. Lingkungan di Visual Basic 5 dan 6 mendukung konsep "Project Group" dan dapat menangani banyak project dalam lingkungan yang sama. Untuk membuat sebuah Project Group, pertama Anda menge-load atau membuat sebuah project seperti biasa, dan kemudian Anda melakukan perintah "Add Project" dari menu File untuk membuat project-project tambahan atau Anda menge-load project yang sudah ada dari disk. Kemampuan ini memberi kemudahan kepada Anda untuk membuat sebuah Project Group yang dibangun oleh satu Standard EXE dan satu atau lebih ActiveX DLL, jadi Anda bisa langsung mengetest/mencoba satu atau lebih component dalam satu proses sekaligus dalam satu waktu yang sama. Anda juga dapat menyimpan Project Groupt tersebut dengan sebuah file dengan ekstensi .vbg, sehingga Anda dapat dengan cepat menge-load semua project dengan satu perintah dari menu "Open".
Ketika Anda menjalankan perintah "Run", project yang telah ditandai sebagai "Startup Project" (lihat Gambar 16-13) akan memulai pengeksekusiannya. Hal ini biasa dalam project "Standard EXE" yang bekerja seperti aplikasi Client dan nantinya meng-instansiasi satu atau lebih object dari project ActiveX DLL. Anda tidak perlu secara eksplisit menjalankan project ActiveX DLL (seperti yang Anda lakukan jika menjalankan component Out-of-Process di lingkungan IDE Visual Basic yang terpisah), tapi Anda masih tetap harus menambahkan reference ke DLL tersebut di kotak dialog menu References... dari project "Standard EXE".



Figure 16-13: Anda dapat membuat sebuah project Startup dengan mengklik kanan pada project tersebut di jendela Project
Hati-hati bahwa beberapa perintah di IDE Visual Basic secara implist mengacu ke project yang aktif, itulah project yang disorot di Properties Project. Sebagai contoh, isi dari kotak dialog References... berlainan tergantung dari project yang mana yang disorot, dan kotak dialog Project Properties membiarkan Anda melihat dan memodifikasi hanya atribut dari project yang sedang digunakan. Ketika project tersebut merupakan project Standard EXE, Object Browser menampilkan hanya class Public dan anggota dari project ActiveX DLL lainnya, dan tidak mengizinkan Anda untuk mengubah atribut-atribut member-nya. Untuk menampilkan semua anggota private atau memodifikasi atribut dan deskripsi dari method dan property DLL, Anda harus membuat project ActiveX DLL sebagai project yang aktif.
Menjalankan file DLL dalam lingkungan yang sama sebagai client-nya bukanlah merupakan sebuah batasan, sebab sebuah DLL ActiveX dapat hanya mempunyai sebuah client. File di-load di space alamat client dan karena itu tidak dapat digunakan oleh aplikasi lainnya. Jika dua aplikasi client meminta object dari component In-Process yang sama, COM meng-instansiasi dua DLL yang berbeda, masing-masing pada space alamat client yang memintanya. Untuk alasan ini, menggunakan sebuah DLL ActiveX jauh lebih mudah daripada menggunakan file component EXE ActiveX; component melayani hanya satu client dan oleh karena itu permintaan-permintaan dapat dengan cepat dipenuhi. Aplikasi client tidak perlu menghitung kondisi waktu "time-out".
Sebuah project ActiveX DLL tidak dapat mengandung class-class SingleUse atau GlobalSingleUse. Alasannya adalah file DLL berjalan di proses yang sama dengan proses Client dan tidak mempunyai sebuah proses miliknya sendiri. Jadi COM tidak dapat membuat sebuah proses untuk file DLL ketika Client membuat sebuah object yang kedua dari component tersebut.

Perbedaan Antara Component In-Process dan Out-of-Process
Component ActiveX DLL tidak dapat melakukan segalanya. Dalam banyak hal, batasan mereka disebabkan oleh sifat in-process alami mereka dan memang tidak diatur oleh Visual Basic.

Penanganan Kesalahan (Error Handling)
Anda menangani error di component in-process seperti yang Anda lakukan dengan file ActiveX EXE Servers. Dalam arti, biar bagaimanapun, penanganan kesalahan di dalam component in-process bahkan lebih penting karena kesalahan atau error yang fatal yang terjadi di server juga akan men-terminasi client dan bersifat buruk karena keduanya sebenarnya adalah proses yang sama.

Antar Muka Pemakai
ActiveX DLL dapat menampilkan form miliknya sendiri, seperti yang dilakukan component Out-of-Process. Yang menarik adalah, sebuah form yang berasal dari sebuah component secara otomatis ditempatkan di depan dari form yang berasal dari aplikasi Client, jadi Anda tidak perlu mengatur dengan menggunakan fungsi API SetForegroundWindow untuk menghasilkan perilaku yang sebenarnya. Tergantung pada kemampuan di Client, biar bagaimanapun, sebuah component in-process mungkin tidak mampu menampilkan form yang nonmodal. Sebagai contoh, program yang dibuat dengan Visual Basic 5 atau 6, semua aplikasi yang berasal dari kumpulan Microsoft Office 97 (atau versi lanjutannya), dan semua aplikasi pihak ketiga yang mempunyai lisensi dengan dukungan VBA, mendukung form nonmodal yang ditampilkan oleh component in-process. Sebaliknya, program yang dibuat dengan Visual Basic 4 dan semua aplikasi dengan versi sebelumnya dari Microsoft Office akan menimbulkan sebuah error nomor 369, ketika sebuah component DLL mencoba untuk menampilkan sebuah form nonmodal.
Visual Basic memungkinkan Anda untuk mencoba apakah sebuah Client mendukung form nonmodal melalui property yang bersifat read-only bernama: App.NonModalAllowed. Microsoft menyarankan agar Anda mencoba property ini sebelum menampilkan sebuah form nonmodal dari dalam sebuah component, dan menurunkannya dengan menampilkan sebuah form jika mungkin:
     If App.NonModalAllowed Then
        frmChart.Show
     Else
        frmChart.Show vbModal
     End If
 
Jika Anda mempertimbangkan bahwa konstanta vbModal adalah 1 (Satu) dan apakah App.NonModalAllowed mengembalikan nilai 0 atau 1, Anda dapat melakukan segalanya dalam satu statement:
     frmChart.Show (1 + App.NonModalAllowed)
 
Sayangnya, Anda tidak dapat mencoba fitur ini tanpa melakukan kompilasi component ke dalam sebuah file ActiveX DLL karena property App.NonModalAllowed selalu mengembalikan nilai True ketika program berjalan di lingkungan Visual Basic.

Mematikan Server
Peraturan bahwa kondisi ketika sebuah component in-process diterminasi adalah berbeda dari apa yang Anda telah lihat untuk component out-of-process. Perbedaan utama adalah bahwa sebuah component in-process selalu mengikuti perilaku Client: Ketika Client menterminasi, component juga men-terminasi, walaupun jika dia memiliki form yang kelihatan. Ketika Client masih tetap mengksekusi, sebuah component in-process diterminasi jika semua dari kondisi berikut bernilai True:
1.    Tidak ada variabel object menunjuk ke sebuah object di component, juga di dalam Client atau di component itu sendiri. (ActiveX EXE server tidak disimpan oleh variabel object yang dimiliki oleh component tersebut).
2.    Tidak ada permintaan untuk sebuah object milik component yang berada di dalam antrian menunggu untuk dilayani.
3.    Server tidak memiliki form yang kelihatan. (ActiveX EXE server tetap disimpan walaupun form itu diload tapi tidak kelihatan).
4.    Server tidak sedang mengeksekusi coding apapun.
Kenyataan bahwa sebuah in-process server tetap hidup juga oleh reference internal ke object-nya sendiri menimbulkan sebuah masalah yang serius. Sebagai contoh, jika component terdiri dari dua object yang mempunyai reference ke setiap object lainnya, component tidak akan pernah dimatikan ketika Client membebaskan semua reference kepadanya. Dengan kata lain, referensi melingkar (circular reference) dapat menjaga sebuah component in-process tetap hidup sampai Client melakukan terminasi. Tidak ada cara yang sederhana untuk mengatasi masalah ini, dan hal ini tergantung kepada sang programmer untuk menghindari membuat circular reference.
Deskripsi penting lainnya dalam perilaku dari component in-process mungkin tidak berorientasi dengan banyak programmer. Ketika component ActiveX EXE diterminasi secepat Client membebaskan semua reference kepadanya (disediakan bahwa semua kondisi lain yang perlu mungkin bertemu), component in-process tidak segera dibebaskan. Secara umum, Visual Basic menjaga mereka tetap hidup untuk beberapa menit (walaupun pada kenyataannya, delay yang terjadi mungkin bervariasi) jadi jika permintaan lainnya datang dari Client, COM tidak harus me-load kembali server. Jika waktu timeout sudah habis, DLL secara diam- diam di-unload dan memory-nya dibebaskan. Sebuah permintaan baru yang datang dari Client pada kondisi ini akan mengambil sedikit waktu lebih karena COM harus meload kembali component tadi.
Perhatian: Hanya reference kepada object yang Public dapat menjaga sebuah component tetap hidup. Walaupun jika sebuah DLL in-process mengatur untuk melewatkan Client-nya sebuah pointer kepada sebuah object Private (sebagai contoh, dengan menggunakan sebuah argumen As Object atau mengembalikan nilai), reference ini tidak akan menjaga component tetap hidup. Jadi jika Client membebaskan semua reference kepada object component public tersebut, setelah beberapa saat component tadi akan di-unload. Variabel yang dimiliki oleh Client menjadi tidak valid dan membuat aplikasi menjadi crash segera ketika variabel tersebut digunakan dengan cara apapun. Untuk alasan ini, sebuah component seharusnya tidak pernah melewatkan sebuah object Private kepada client-nya.

Pemberian Jalan Masuk
Pemanggilan kepada sebuah method milik component in-process atau properties akan dilayani sessegera mungkin, walaupun jika component tersebut sedang melayani permintaan lainnya. Perbedaan ini berasal dari bagaimana component out-of-process mempunyai perilaku dan membangkitkan sejumlah persoalan yang harus Anda perhitungkan untuk:
1.    Jika Client memanggil sebuah method selagi component sedang melayani sebuah permintaan sebelumnya, pemanggilan pertama akan dihentikan sampai permintaan kedua selesai dilayani. Hal ini berarti bahwa permintaan-permintaan dilayani secara berlawanan dari kedatangannya. (ActiveX EXE Server selalu melayani permintaan client secara serial).
2.    Jika component sedang menampilkan sebuah form modal, dia tidak dapat melayani permintaan apapun yang datang dari Client. (ActiveX EXE servers tidak mempunyai masalah ini).
Seperti yang Anda lihat, kedua masalah di atas disebabkan oleh kenyataan bahwa Client memanggil component selagi dia melayani sebuah permintaan sebelumnya. Hal ini dapat terjadi: jika component mengeksekusi sebuah perintah DoEvents yang membiarkan Client menjadi aktif kembali, jika component membangkitkan sebuah event di dalam aplikasi Client-nya, atau jika Client memanggil component dari dalam sebuah event procedure Timer milik control Timer. Apabila Anda mengabaikan hal ini, Anda seharusnya tidak pernah mengalami masalah jalan masuk. Alternatif lainnya, Anda dapat mengimplementasikan sebuah tanda, sebuah variabel global di dalam Client yang menjaga jalur ketika dia aman untuk memanggil component.

Perbedaan Antara ActiveX DLL dan Standard EXE Programs
Anda seharusnya menjaga beberapa fitur lagi dari perilaku sebuah component in-process; hal ini penting ketika meng-konversi beberapa classes dari sebuah aplikasi Visual Basic standar ke dalam sebuah component ActiveX DLL. Sebagai contoh, sejumlah object dan kata kunci merefer ke lingkungan component, bukan milik Client:
1.    Fungsi Command selalu mengembalikan sebuah string kosong jika digunakan di dalam sebuah component in-process karena DLL tidak pernah dipanggil dengan sebuah argumen level command.
2.    Object App dan Printer dan Form Collection bersifat private ke component dan tidak terpengaruh oleh object dengan nama yang sama di aplikasi Client.
3.    Aplikasi utama dan component ActiveX tidak membagi nomor file, jadi Anda tidak dapat membuka sebuah file di dalam aplikasi utama dan memiliki data DLL yang dikirim kepadanya.
4.    Properties Screen.ActivateForm dan Screen.ActiveControl tidak dapat melihat langsung batas component; karenanya, mereka mengembalikan even Nothing jika Client sedang menampilkan sebuah form, dan mereka dapat mengembalikan sebuah reference ke sebuah form yang kelihatan di dalam DLL walaupun jika mereka tidak sedang aktif.
Beberapa fitur lainnya yang tidak berfungsi seperti layaknya yang mereka lakukan adalah:
1.    Component in-process tidak men-support operasi DDE (Dynamic Data Exchange).
2.    Reference apapun yang mengacu ke properties App.OLEServerxxx akan menyebabkan sebuah error bernomor 369, "Operation not valid in an ActiveX DLL".
3.    Ketika Client melakukan terminasi, event QueryUnload atau Unload tidak dibangkitkan untuk form yang masih diload di memory.

Menambahkan Forms di Sebuah File DLL
ActiveX DLL Servers menawarkan suatu cara yang hebat untuk menggunakan kembali form-form umum dan kotak dialog. Seperti yang Anda tahu, module form tidak dapat menjadi Public, jadi mereka tidak dapat kelihatan dari luar project. Tapi Anda dapat membuat sebuah Class yang membungkus sebuah form dan menampilkan antarmuka yang sama dan kemudian membuat Class Public sehingga Anda dapat membuatnya dari aplikasi lain. Aplikasi yang sudah ada membutuhkan sedikit atau tanpa modifikasi sama sekali untuk menggunakan component menggantikan form. Satu-satunya kebutuhan untuk melakukan hal ini, pada kenyataannya, adalah bahwa sebuah aplikasi tidak pernah secara langsung me-reference controls di atas form, yang merupakan sesuatu yang seharusnya tidak Anda lakukan untuk melindungi enkapsulasi form.
Katakanlah Anda telah membuat sebuah form bernama "frmLogin" yang menerima sebuah nama user dan password lalu mem-validasi keduanya. Dalam contoh yang sederhana ini, nama user yang valid bernama francesco, dan password yang valid adalah: balena. Form memiliki dua control TextBox, masing-masing bernama "txtUserName" dan "txtPassword", dan sebuah tombol Commandbutton bernama "cmdOK". Form juga mengeksekusi sebuah event, bernama "WrongPassword" yang akan dibangkitkan ketika user mengklik tombol "cmdOK" dan nama user atau password-nya tidak valid (salah). Event ini akan ditangkap oleh coding Client untuk menampilkan sebuah MsgBox kepada user, seperti yang Anda lihat di gambar Figure 16-14. Source code selengkapnya dari module form tersebut adalah:
     Event WrongPassword(Password As String)
     Public UserName As String
     Public Password As String

     Private Sub cmdOK_Click()
       'Validasi password.
       If LCase$(txtUserName= "francesco" And LCase$(txtPassword) = _
          "balena" Then
          Unload Me
       Else
          RaiseEvent WrongPassword(txtPassword)
       End If
     End Sub

     Private Sub Form_Load()
       txtUserName = UserName     'Load properties ke dalam fields.
       txtPassword = Password
     End Sub

     Private Sub Form_Unload(Cancel As Integer)
       UserName = txtUserName     'Load nilai field ke dalam properties.
       Password = txtPassword
     End Sub
 
Anda dapat menggunkana form ini seperti jika dia bertindak sebagai sebuah Class, tanpa langsung mereference ke control yang terdapat di atasnya. Berikut coding dari form utama di program demo yang bertalian:
     Dim WithEvents frmLogin As frmLogin

     Private Sub Command1_Click()
       Set frmLogin = New frmLogin
       frmLogin.Show vbModal
       MsgBox "User " & frmLogin.UserName & " logged in", vbInformation
     End Sub
 
     Private Sub frmLogin_WrongPassword(password As String)
       MsgBox "Wrong Password"
     End Sub
 



Figure 16-14: Sebuah component in-process dapat tepat meng-enkapsulasi sebuah form yang dapat digunakan kembali dan menampilkan event-nya ke aplikasi Client.
Karena form dapat digunakan tanpa mengakses control-control yang terdapat di dalamnya, Anda sekarang dapat membuat sebuah Class Module bernama "CLogin" di luar form "frmLogin" dan meng-enkapsulasi baik class dan form di dalam sebuah file DLL "LoginSvr" yang menampilkan fungsionalitas form ke luar. Source code dari class "CLogin" adalah sebagai berikut:
     Event WrongPassword(Password As String)
     Private WithEvents frmLogin As frmLogin

     Private Sub Class_Initialize()
       Set frmLogin = New frmLogin
     End Sub

     Public Property Get UserName() As String
       UserName = frmLogin.UserName
     End Property

     Public Property Let UserName(ByVal newValue As String)
       frmLogin.UserName = newValue
     End Property

     Public Property Get Password() As String
       Password = frmLogin.Password
     End Property

     Public Property Let Password(ByVal newValue As String)
       frmLogin.Password = newValue
     End Property

     Sub Show(Optional mode As Integer)
       frmLogin.Show mode
     End Sub

     Private Sub frmLogin_WrongPassword(Password As String)
       RaiseEvent WrongPassword(Password)
     End Sub
 
Seperti yang Anda lihat, properties UserName dan Password dan method Show dari Class mendelegasikan dengan sederhana ke anggota form dengan nama yang sama. Lebih dari itu, Class menangkap event "WrongPassword" yang berasal dari form dan membangkitkan sebuah event dengan nama yang sama di aplikasi Client. Ringkasnya, Class menampilkan interface yang sama seperti form aslinya. Jika Anda menge-set atribut Instancing menjadi "5-MultiUse", Class (dan juga form) dapat digunakan kembali oleh aplikasi Client apapun. Anda hanya harus mengubah beberapa baris coding di dalam aplikasi Client agar dapat berfungsi dengan class CLogin menggantikan Class frmLogin. (Coding yang dimodifikasi dicetak tebal).
     Dim WithEvents frmLogin As CLogin

     Private Sub Command1_Click()
       Set frmLogin = New CLogin
       frmLogin.Show vbModal
       MsgBox "User " & frmLogin.UserName & " logged in", vbInformation
     End Sub

     Private Sub frmLogin_WrongPassword(password As String)
       MsgBox "Wrong Password"
     End Sub
 
Anda dapat menggunakan cara ini untuk membuat baik form yang dapat digunakan baik yang modal maupun modeless. Anda tidak dapat, biar bagaimanapun, menggunakan form-form yang dibuat dalam sebuah file DLL sebagai form MDI Child di dalam sebuah aplikasi MDI.

Performansi
Anda dapat mencoba performansi dari ActiveX DLL Server Anda dengan cara-cara berikut:

Melewatkan Data
Karena file DLL berjalan di space alamat yang sama sebagai Client-nya, COM tidak perlu untuk mengatur data yang sedang dilewatkan dari Client ke component dan sebaliknya. Sebenarnya, peran dari COM dengan component in-process jauh lebih sederhana daripada dengan out-of-process server, karena COM hanya harus meyakinkan bahwa DLL diinstansiasi dengan benar ketika Client meminta sebuah object darinya. Dari situ maju, Client melakukan komunikasi langsung dengan component. COM akan menjadi aktif lagi hanya untuk menjamin bahwa DLL dibebaskan ketika Client tidak membutuhkannya lagi.
Pergantian proses yang terjadi kapanpun sebuah Client memanggil sebuah component out-of-process membuat lambat component ActiveX EXE dengan pertimbangan. Sebagai contoh, memanggil sebuah procedure kosong tanpa argumen apapun di dalam sebuah component out-of- process adalah sekitar 500 kali lebih lambat daripada memanggil sebuah procedure kosong di dalam sebuah DLL in-process! Yang mengejutkan, sebuah method di sebuah file DLL mengambil lebih kurang dari waktu yang sama sebagai sebuah method di dalam sebuah class Private milik aplikasi Client, yang membuktikan bahwa pemanggilan yang berlebihan terhadap sebuah permintaan kepada sebuah component in-process adalah negligible
Ketidakadaan dalam pengaturan juga menyarankan bahwa aturan optimatisasi untuk melewatkan data ke sebuah DLL in-process mungkin berbeda dari apa yang seharusnya Anda ikuti ketika bekerja dengan EXE server out-of-process. Sebagai contoh, tidak ada perbedaan yang berarti antara melewatkan sebuah nomor ke sebuah procedure in-process dengan menggunakan kata kunci ByRef atau ByVal. Tapi sebaiknya Anda melewatkan string yang lebih panjang secara ByRef daripada ByVal: Saya membuat sebuah program percabangan sederhana yang membandingkan performansi dari in-process dan out-of-process server. Saya menemukan bahwa melewatkan sebuah string sebanyak 1000 karakter dengan menggunakan ByVal dapat 10 kali lebih lambat daripada jika melewatkan dengan menggunakan ByRef. Dan string yang lebih panjang lebih lambat dilewatkan dengan menggunakan ByVal.

Mengeset Base Address DLL
Jika Anda mempunyai banyak Client yang menggunakan component in-process yang sama pada waktu yang sama, sebuah instansiasi terpisah dari DLL diload di setiap space alamat Client. Hal ini mungkin mengakibatkan pemborosan memory, kecuali Anda mengambil beberapa tindakan pencegahan.
Bersyukurlah kepada fitur-fitur yang advanced dari sub sistem virtual memory Windows. Anda dapat menge-load DLL yang sama dalam satu space alamat tanpa menggunakan lebih banyak memory dari yang dibutuhkan dengan sebuah instansiasi DLL. Lebih tepat lagi, aplikasi Client yang banyak dapat berbagi image yang sama dari DLL yang diload dari disk. Hal ini mungkin, bagaimanapun, hanya jika semua instansiasi dari DLL di-load pada alamat yang sama di space memory dari proses yang berbeda dan jika alamat ini bersamaan dengan base address DLL.
Base address dari sebuah DLL adalah default alamat di mana Windows mencoba meload file DLL dengan space alamat dari Client-nya. Jika usaha tersebut berhasil, Windows dapat mengeload DLL dengan cepat karena dia hanya memesan sebuah tempat di memory dan me-load isi dari file DLL di sana. Di pihak lain, jika Windows tidak dapat menge-load DLL di base-address-nya (kebanyakan karena area tersebut telah dialokasikan kepada DLL lainnya), Windows harus menemukan sebuah block yang bebas di memory yang cukup besar untuk mengisi DLL, dan kemudian dia harus meng-alokasi ulang code DLL. Proses perubahan pengalokasian ulang alamat lompatan dan pemanggilan instruksi di code binary DLL membutuhkan waktu untuk menge-load alamat yang berbeda dari file DLL tersebut.
Kesimpulannya, mengapa jauh lebih baik bahwa sebuah DLL di-load pada base-address-nya, ada dua alasan utama:
1.    Proses untuk me-load biasanya lebih cepat karena tidak ada alokasi ulang.
2.    Windows dapat menyimpan memory jika proses lain telah me-load DLL yang sama karena instansiasi yang banyak dari DLL yang di-share satu blok fisik dari memory yang menangani image DLL seperti jika disimpan di disk.
Visual Basic mengizinkan Anda untuk memilih base-address untuk sebuah DLL server in-process melalui tab "Compile" dari kotak dialog Project Properties, seperti yang dapat lihat pada gambar Figure 16-15. Nilai default untuk alamat ini adalah H11000000, tapi saya menyarankan Anda dengan sangat untuk mengubahnya sebelum Anda meng-compile versi terakhir dari component Anda. Jika tidak, base-address DLL Anda akan konflik dengan DLL lainnya yang dibuat dengan Visual Basic. Hanya satu DLL dapat "menang", dan semua yang lainnya akan di-alokasi ulang.



Figure 16-15: Anda dapat mengatur performansi ActiveX DLL dengan mengganti base-address-nya...
Untungnya, bahasa pemrograman lainnya berbeda untuk nilai base-address tersebut. Sebagai contoh, DLL yang dibuat dengan menggunakan Microsoft Visual C++, default base-address-nya H10000000, jadi walaupun jika programer mereka tidak mengganti setting default tersebut, DLL tersebut tidak akan bentrok/konflik dengan yang dibuat menggunakan Visual Basic.
Ketika Anda sedang memutuskan base-address yang mana yang seharusnya dipilih untuk sebuah file DLL Visual Basic, sebaiknya Anda melakukan perhitungan sebagai berikut:
1.    DLL menggunakan sebuah bilangan Integer dari 64 KB pages, jadi seharusnya Anda membiarkan empat karakter terakhir sebagai 0 (nol) (64 KB = &H10000).
2.    Setiap proses Windows dapat menggunakan sebuah ruang alamat 4 GB, tapi area di bawah 4 GB dan di atas 2 GB "dipesan" untuk Windows.
3.    File executable Windows diload pada alamat mulai 4 MB (&h500000). Sebagai contoh, sebuah base-address yang lebih besar dari 1 GB (&h50000000) mengakomodasi aplikasi Client terbesar yang dapat Anda bangun dan masih menyisakan 1 GB untuk DLL Anda. Bahkan setelah perhitungan ukuran 64 KB pages, hal ini menyisakan kepada Anda nilai 16.384 yang berbeda untuk memilih ketika peng-assign-an sebuah base-address ke DLL Anda.

Pemanjangan Sebuah Aplikasi dengan DLL Pengiring
ActiveX DLL Server sangat berguna untuk menambah fungsionalitas dari sebuah aplikasi, hal inilah yang disebut DLL Pengiring. Untuk memahami mengapa DLL pengiring sangat bermanfaat, pertama mari kita lihat apa itu "resource files".

Resource Files
Resource files adalah files juga, biasanya memiliki ekstensi .res, yang dapat mengandung strings, images, dan data biner yang digunakan oleh sebuah aplikasi. Anda membuat resource files dengan dua langkah. Pertama, Anda persiapkan sebuah file teks (dengan ekstensi .rc) yang mengandung deskripsi dari isi resource file. File teks ini harus mengikuti aturan sintaks yang tepat. Sebagai contoh, berikut ini sepenggal dari sebuah RC file yang mendefinisikan dua strings dan satu bitmap:
     STRINGTABLE
     BEGIN
         1001  "Welcome to the Imaging application"
         1002  "Do you want to quit now?"
     END
     2001      BITMAP c:windowsclouds.bmp
 
Langkah kedua, Anda meng-compile file .rc ke dalam sebuah file .res, dengan menggunakan compiler RC.EXE dengan menambahkan /r pada baris perintah tersebut. Utility ini sudah ada dengan Visual Basic. File RC.EXE terdapat di sub direktori "Wizards". Jika di PC Anda terinstall Microsoft Visual Studio 6, file RC.EXE ini berada di dalam direktori: "C:Program FilesMicrosoft Visual StudioVB98Wizards".
     RC /r TEST.RC
 
Di akhir proses compilasi, Anda mendapatkan sebuah file .res dengan nama yang sama seperti nama file .rc-nya (dalam contoh ini test.res). Anda sekarang dapat me-load file baru ini ke dalam lingkungan Visual Basic dengan menggunakan perintah Add File di menu Project.
Visual Basic 6 menyederhanakan pembuatan resource file dan fase compilasi dengan menggunakan sebuah add-in baru, "VB Resource Editor", seperti yang ditunjukkan pada gambar Figure 16-16. Add-in ini juga mendukung "multiple string tables", yang mengizinkan aplikasi Anda menyesuaikan diri ke bahasa pengguna secara otomatis. Add-in di Visual Basic versi 5 juga tersedia untuk didownload dari Web Site Microsoft.



Figure 16-16: VB Resource dapat membuat resource files dengan bitmaps, icons, suara, dan multiple string tables
Setelah Anda membuat sebuah file .res, Coding Anda dapat mengacu ke file resource dengan menggunakan fungsi LoadResString, LoadResPicture, dan LoadResData, seperti yang ditunjukkan di contoh bawah:
     'Cetak pesan selamat datang.
     Print LoadResString(1001)
     'Ambil sebuah gambar ke dalam control PictureBox.
     Picture1.Picture = LoadResString(2001, vbResBitmap)
 
Resource files adalah sebuah pilihan yang tepat ketika Anda sedang membuat sebuah aplikasi yang harus digunakan di negara lain. Source code bersifat terpisah dari semua strings dan gambar yang digunakan oleh program, dan ketika Anda ingin membuat sebuah versi baru dari aplikasi tersebut untuk sebuah negara yang berbeda, Anda hanya harus menyiapkan sebuah resource file yang berbeda. Untuk mempelajari lebih jauh mengenai Resource Files, silahkan Anda lihat contoh project ATM.VBP yang ada bersama Visual Basic 6.
Walaupun dengan bantuan dari Add-In VB Resource Editor, biar bagaimanapun, bekerja dengan Resource Files agak tidak praktis untuk beberapa alasan berikut:
1.    Sebuah project Visual Basic dapat menyertakan hanya satu resource file; jika sebuah aplikasi harus mendukung terhadap beberapa bahasa pada saat yang sama, Anda harus merencanakan sebuah skema pengindeksan. (Lihat aplikasi ATM Visual Basic untuk sebuah contoh yang menggunakan teknik ini).
2.    Anda tidak dapat mengganti resource file dari sebuah aplikasi tanpa meng-compile ulang aplikasi.
Kedua masalah di atas dapat diatasi dengan menggunakan DLL Pengiring.
Satellite DLLs (DLL Pengiring)
Konsep tentang asal DLL Pengiring ini adalah sederhana: Menggantikan dari meloading strings dan sumber daya lainnya dari Resource Files, Anda menge-load-nya dari sebuah ActiveX DLL. Trik-nya adalah: Instansiasi sebuah object dari DLL dengan menggunakan CreateObject menggantikan kata kunci New, dan oleh karenanya, Anda dapat memilih DLL yang Anda load pada saat run-time. Pendekatan ini mengizinkan Anda untuk menyerahkan DLL ke pelanggan Anda walaupun setelah mereka selesai menginstall aplikasi utama, jadi Anda dapat dengan efektif menambahkan "support" (pendukung) untuk bahasa baru segera setelah Anda membuat DLL baru. User dapat mengganti dari satu DLL ke yang lainnya pada saat run-time. Sebagai contoh, dengan menggunakan sebuah perintah menu.
Penulis telah menyiapkan sebuah aplikasi demo yang menggunakan DLL Pengiring untuk membuat sebuah program database sederhana yang mempunyai antarmuka sesuai dengan negara si pemakai. (Lihat gambar Figure 16-17). Ketika aplikasi dimulai, dia akan memilih DLL yang cocok dengan versi Sistem Operasi Windows yang sedang digunakan atau default-nya ke versi Inggris jika tidak ada DLL untuk bahasa yang ada ditemukan.



Figure 16-17: Sebuah aplikasi multi-bahasa yang menggunakan DLL Pengiring untuk mendukung baik bahasa Inggris maupun bahasa Italia.
Sebuah DLL Pengiring yang meng-ekspor strings, bitmaps, dan data biner harus menampilkan sedikitnya tiga fungsi. Untuk membuat DLL Pengiring kelihatan seperti Resource Files, Anda dapat menamakan mereka LoadResString, LoadResPicture, dan LoadResData. Berikut potongan dari source code dari DLL yang digunakan oleh contoh aplikasi:
     ' The Resources class module in the Application000 project
     Enum ResStringID
       rsDataError = 1
       rsRecord
       rsPublishers
     ' (Other enumerated values omitted...)
     End Enum

     Enum ResPictureID
       rpFlag = 1
     End Enum

     Enum ResDataID
       rdDummy = 1        ' This is a necessary placeholder.
     End Enum

     Function LoadResString(ByVal ID As ResStringID) As String
        Select Case ID
          Case rsPublishers: LoadResString = "Publishers"
          Case rsClose: LoadResString = "&Close"
          Case rsRefresh: LoadResString = "&Refresh"
          ' (Other Case clauses omitted...)
        End Select
     End Function

     Function LoadResPicture(ByVal ID As ResPictureID, _
       Optional Format As Long) As IPictureDisp
       ' Loads images from the frmResources form
       Select Case ID
          Case rpFlag: Set LoadResPicture = _
               frmResources000.imgFlag.Picture
       End Select
     End Function

     Function LoadResData(ByVal ID As ResDataID, _
              Optional Format As Long) As Variant
     ' Not used in this sample program
     End Function
 
DLL yang sebenarnya ini terdiri dari satu bitmap dan tidak menyertakan data biner apapun. Agar lebih sederhana, bitmap telah di-load saat design-time di sebuah control Image pada form frmResource. Form ini tidak pernah ditampilkan dan bekerja hanya sebagai sebuah kontainer untuk bitmap. Anda dapat menggunakan pendekatan ini juga untuk menempatkan icons dan cursors. Jika Anda perlu menempatkan tipe data biner lainnya, biar bagaimanapun, Anda dapat menggunakan sebuah resource file. Dalam hal ini, setiap DLL Pengiring mempunyai resource file sendiri.
Trik yang menggunakan DLL Pengiring menggunakan DLL utama (yaitu DLL yang menyediakan resource untuk bahasa default - dalam contoh ini bahasa Inggris) sebagai antar muka DLL ke bahasa lainnya harus diimplementasikan. Mari kita lihat bagaimana DLL Italia diimplementasikan:
     ' The Resources class module in the Application410 project
     Implements MyApplication000.Resources

     Private Function Resources_LoadResString(ByVal ID As _
         MyApplication000.ResStringID) As String
         Dim res As String
         Select Case ID
             Case rsPublishers: res = "Editori"
             Case rsClose: res = "&Chiudi"
             Case rsRefresh: res = "&Aggiorna"
             ' (Other Case clauses omitted...)
         End Select
         Resources_LoadResString = res
     End Function

     Private Function Resources_LoadResPicture(ByVal ID As _
         MyApplication000.ResPictureID, Optional Format As Long) _
         As IPictureDisp
         Select Case ID
             Case rpFlag: Set Resources_LoadResPicture = _
                 frmResources410.imgFlag.Picture
         End Select
     End Function

     Private Function Resources_LoadResData(ByVal ID As _
         MyApplication000.ResDataID, Optional Format As Long) As Variant
         ' Not used in this program
     End Function
 
Catatan: Class ini tidak mempunyai anggota di antar muka utamanya. DLL Italia ditempatkan di sebuah project bernama MyApplication410.vbp, di mana default DLL ditempatkan di sebuah project bernama MyApplication000.vbp. Alasan untuk skema penamaan ini akan diterangkan berikut ini.

Aplikasi Client Locale-Aware
Mari kita lihat bagaimana sebuah aplikasi Client dapat mengambil kekuatan dan kefleksibelan dari DLL Pengiring untuk mengadaptasi dirinya secara otomatis ke user sementara dia masih menyediakan mereka dengan kemampuan untuk menukar ke sebuah bahasa yang berbeda saat run-time. Rahasia berada di dalam fungsi API, GetUserDefaultLangID, yang mengembalikan penanda locale dari pemakai yang ada dan aktif. Aplikasi Client menggunakan nilai ini untuk membangun nama DLL dan kemudian melewatkannya ke fungsi CreateObject, seperti coding yang ditunjukkan di bawah:
     ' The main BAS module in the client application
     Declare Function GetUserDefaultLangID Lib "kernel32" () As Long

     Public rs As New MyApplication000.Resources

     Sub Main()
         InitLanguage              ' Load the satellite DLL.
         frmPublishers.Show        ' Show the startup form.
     End Sub

     ' Load the satellite DLL that corresponds to the current user's locale.
     Sub InitLanguage()
         Dim LangId As Long, ProgID As String
         ' Get the default language.
         LangId = GetUserDefaultLangID()
         ' Build the complete class name.
         ProgID = App.EXEName & Hex$(LangId) & ".Resources"
         ' Try to create the object, but ignore errors. If this statement
         ' fails, the RS variable will point to the default DLL (English).
         'coding ini shrsnya jika error lanjut saja, sengaja dihilangkan spy dapat diupload ke brinkster
         Set rs = CreateObject(ProgID)
      End Sub
 
Kunci dari teknik ini berada di dalam procedure InitLanguage di mana aplikasi membangun secara dinamik nama dari DLL yang akan menyediakan resource untuk locale yang ada. Sebagai contoh, ketika dieksekusi di bawah versi Windows Italia, fungsi API yang bernama GetUserDefaultLangID mengembalikan nilai 1040, atau &h510.
Anda dapat membuat DLL Pengiring untuk bahasa lainnya dan mengirim mereka ke pelanggan Anda di luar negeri. Pendekatan ini selalu bekerja sempurna, disediakan bahwa Anda meng-assign sebuah project dengan nama seperti MyApplicationXXX, di mana XXX adalah bilangan hexadecimal untuk penanda locale. (Untuk melihat daftar pengenal locale, lihat Windows SDK Documentation). Bagian pertama dari nama project harus cocok dengan nama project aplikasi Client (dalam contoh ini: MyApplication), tapi Anda dapat merencanakan cara efektif lainnya untuk membangun nama DLL secara dinamis.
Jika fungsi CreateObject gagal, variabel rs tidak akan diinisialisasi dalam prosedur InitLanguage, tapi karena dia dideklarasikan sebagai sebuah variabel yang bersifat "auto-instancing variabel", dia otomatis menginstansiasi component default MyApplication000.Resource. Kunci utamanya adalah bahwa semua DLL Pengiring untuk aplikasi yang ada mengimplementasikan antarmuka yang sama, jadi variabel rs dapat memegang sebuah reference ke Pengiring DLL lainnya dengan menggunakan binding sebelumnya. Lihat bagaimana variabel rs digunakan di dalam sebuah form dari aplikasi Client:
     Private Sub Form_Load()
         LoadStrings
     End Sub

     Private Sub LoadStrings()
         Me.Caption = rs.LoadResString(rsPublishers)
         cmdClose.Caption = rs.LoadResString(rsClose)
         cmdRefresh.Caption = rs.LoadResString(rsRefresh)
         ' (Other string assignments omitted...)
         Set imgFlag.Picture = rs.LoadResPicture(rpFlag)
     End Sub
 
Karena Class MyApplication000.Resource mendeklarasikan konstanta enumerasi untuk semua string dan resource lain di DLL Pengiring, Anda dapat menggunakan IntelliSense untuk mempercepat fase pengembangan dan menghasilkan sebuah dokumentasi coding sendiri yang dapat dibaca pada saat yang sama.

1 komentar:

Unknown mengatakan...

MAKASIH Gan Informasinya sangat-sangat Membantu dan Berguna.
Mohon Izin Copy-Paste Gan untuk Documment Pribadi saya.

Posting Komentar

:a: :b: :c: :d: :e: :f: :g:
:h: :i: :j: :k: :l: :m: :n: :o: :p:

 
Design by Puskom Corporation Software | Bloggerized by Author's By : Indro Dwi Saputro - Copyright 2012