Thursday, January 8, 2015

Fixing "Fatal Error LNK1123 : Failure During Conversion to COFF, File Invalid or Corrupt" in VS 2010

Seperti terlihat pada judul entrinya, disini akan diperlihatkan cara untuk menangani error pada visual studio 2010 untuk lnk1123 tersebut. Sebelumnya error tersebut terjadi karena ada beberapa hal. Kalau saya sendiri, error tersebut terjadi karena microsoft net framework yang ada di PC diupgrade ke 4.5. Sedangkan visual studio 2010 sendiri menggunakan versi yang lebih lama. Nah pada saat kita akan menjalankan program C++(MFC) di visual studio tersebut, maka error tersebut akan terjadi. Tapi untuk program yang buat C# normal-normal saja. Hal lain yang dapat menyebabkan error seperti ini adalah apabila kita mempunyai visual studio 2010 dan visual studio yang lebih baru misalnya 2012 atw 2013 di PC. Kemudian kita akan menjalankan program C++ di vs 2010, nah kondisi seperti ini pun dapat menghasilkan error link1123.

Sebenarnya error tersebut terjadi karena linker visual studio berusaha menjalankan file cvtres.exe. Ketika net framework terupgrade, maka cvtres.exe terjadi ada 2 biji, satu dari VS 2010 dan satunya lagi dari net framework yang baru. Kemudian karena cvtres.exe ada yang terupdgrade maka cvtres.exe yang lama tidak dapat digunakan lagi padahal path visual studio 2010 itu masih terhubung ke cvtres.exe yang versi lama.

Jadi solusinya adalah atur kembali path visual studio ke cvtres.exe yang baru. Solusi lain yang dapat digunakan adalah mengubah nama cvtres.exe tersebut, misalnya ke cvtres-old.exe. Jika telah diubah, maka visual studio secara otomatis akan mencari cvtres.exe versi yang terbaru sehingga pengaturan pathnya tidak usah kita handle sendiri. Ngomong-ngomong, disini digunakan teknik yang kedua, yaitu mengubah nama cvtres.exe menjadi cvtres-old.exe. Jadi silahkan buka lokasi file tersebut, kalo di PC yang saya gunakan lokasinya ada di C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin, seperti terlihat di bawah :


Nah silahkan ubah file cvtres.exe tersebut. Click continu aja jika harus memperoleh administrator permission :
Setelah diubah :

Sampai disini, ketika program C++ (MFC) kita jalankan kembali, maka error lnk1123 tersebut sudah tidak ada dan program dapat kembali berjalan normal.



Sekian... semoga bermanfaat.... :-)

Wednesday, January 7, 2015

Background Worker Part II - C# WPF

Pada kesempatan kali ini akan dipelajari kembali tentang bagaimana menggunakan background worker di C# menggunakan visual studio 2010. Postingan ini adalah postingan yang kedua tentang background worker. Untuk postingan yang pertama bisa dilihat disini. Postingan tidak terlalu berhubungan dengan postingan pertama tadi, soalnya disini kita akan mulai membuat project baru lagi. Namun ada baiknya jika postingan pertama untuk dicoba dulu sebelum melangkah untuk mempelajari background worker yang akan diperlihatkan pada bagian ini.

Secara ringkas, background worker yang akan diperlihatkan pada postingan ini adalah bagaimana menghentikan thread background worker yang sedang berjalan dan memulai kembali thread yang baru dalam satu tombol saja. Jika kita searching di om gugel kn umumnya pake dua tombol untuk start dan satunya lagi untuk stop, jadi untuk tiap event-eventya jadi mudah. Tapi klu cuma pke 1 tombol ceritanya agk beda dikit. Ok... Langsung saja kita buat project baru di visual studio :


Kemudian tambahkan 1 buah button, 1 textbox, 1 listbox, 1 progress bar, 1 label (tempatkan label di atas progress bar). Kemudian atur posisinya :


Kemudian nama dari masing-masing komponen saya ubah seperti terlihat di bawah :

Next, mari kita tambahkan handler buat tombol start. Untuk itu silahkan double klik tombolnya untuk melangkah ke file c#-nya. Emm... Sebelumnya tambahkan dulu variabel backgroudworker baru :
Di line number 23, dibuat variabel baru dengan nama worker. worker inilah yang akan kita gunakan untuk melakukan background process nantinya. Kemudian didalam fungsi startButton_Click(), tambahkan kode berikut {selalu perhatikan line number untuk setiap kode}:
Ketika button start di klik oleh user, maka pada line 34, variabel worker dicek, apakah sedang berjalan (kondisi busy) atau tidak. Nah jika worker tersebut mempunyai thread (sedang running), maka pada line 36, worker tersebut segera dihentikan dengan command "CancelAsync". Dengan dieksekusinya CancelAsync maka pada thread worker yang sedang running dapat mendeteksi jika thread ini harus dihentikan. Caranya diperlihatkan kemudian. Intinya worker.CancelAsync tersebut memberikan sinyal yang menunjukkan adanya perintah untuk menghentikan thread background worker yang sedang running. Kemudian pada line 39, kita membuat variabel baru dengan nama max tipe integer. Variabel max ini berguna untuk menyimpan angka yang dinput oleh user pada textbox (name="number") mainwindow. Angka dari textbox tersebut diambil dengan menggunakan fungsi Convert.ToInt32(). Fungsi convert tersebut ditambahkan eksepsi untuk menghandle user yang memasukkan selain angka pada textboxt. Eksepsinya seperti terlihat di atas yang terdiri dari format exception dan overflowexception. Format exception terjadi apabila user memasukkan huruf-huruf alphabet ke dalam textbox dan overflow exception terjadi apabila user memasukkan angka yang terlalu besar yang ukurannya tidak bisa ditampung pada variabel tipe integer di C#. Kemudian pada line 52, "Debug.Writeline(max)", kode ini hanya memperlihatkan nilai max ke dalam konsole output di visual studio. Terus pada line 54, "field.Items.Clear();", kode ini berguna untuk menghapus angka-angka pada listbox. Jadi setiap tombol startButton diklik, listboxnya akan dibersihkan hehe... :D. Nah kemudian pada line 56, worker kembali di cek, jika worker sedang tidak running, worker tersebut akan dirunning kembali dengan thread backgroundworker yang baru. Kode ini berguna ketika tombol start pertama kali diklik atau diklik setelah thread backgroundworker sudah selesai dijalankan, kondisi seperti itu kan tidak ada thread, jadi kode diline 58 dapat dieksekusi.

Next, ditambahkan 3 buah fungsi pendukung untuk background worker seperti terlihat di bawah :
Penjelasan untuk ketiga fungsi diatas mungkin hampir sama pada postingan sebelumnya tentang background worker dan proggress bar. Tapi tidak mengapa diulang lagi disini :-D. Jadi fungsi threadProcess adalah fungsi yang pertama kali di jalankan ketika thread backgroundworker pertama kali running. Fungsi ini menjalankan aktivitas utama dalam thread dan menjadi sumber event/sinyal untuk menjalankan fungsi yang lainya seperti updateGUI. Method threadProcess ini jugalah yang digunakan untuk mendeteksi adanya perintah untuk menghentikan thread backgroundworker. Pada line 67 pada fungsi threadProcess ini, dibuat variabel bernama args untuk menyimpan angka dari user (yang diambil dari variabel max pada fungsi startButton_Click). Angka tersebut dibawa oleh variabel input e seperti terlihat pada fungsi di atas. Sebagai catatan variabel input e tersebut tidak hanya dapat membawa tipe integer saja, tapi tipe-tipe yang lain juga seperti string, char, double, dsb. Terus untuk line 68, disitu dibuat variabel mBilGanjil yang nantinya digunakan untuk menyimpan jumlah bilangan ganjil dari 0 sampai args.

Line 70 dibuat loop dari 0 sampai args. Loop ini adalah aktivitas utama yang dilakukan thread backgroundworker yang kita buat. Di dalam loop ini pertama kali dihitung presentasi yang akan ditampilkan pada progress bar dan label untuk presentasi progress bar. Yang perlu diperhatikan nilai i/args dikonvert ke double terlebih dahulu sebelum dikalikan 100. Hal ini untuk mencegah pembulatan yang akan menimbulkan progress bar menjadi tidak smooth.

Line 74, nilai i dicek dengan menggunakan modulo 2, jika 1 bagi 2 ternyata sisanya tidak sama dengan 0 berarti i tersebut adalah bilangan ganjil yang mengakibatkan pertambahan 1 angka pada mBilGanjil. Setelah itu di line 77, terdapat fungsi ReportProgress yang merupakan fungsi bawaan dari background worker yang berguna untuk memberikan sinyal kepada fungsi updateGUI untuk segera dijalankan. Jadi ketika fungsi ReportProgress dipanggil maka fungsi updateGUI akan dijalankan. Nah kita lihat di fungsi ReportProgress tersebut terdapat variabel input berupa presentasi dan i. Variabel presentasi nantinya akan digunakan untuk mengupdate tampilan pada progress bar dan presentasi label progress bar, sedangkan i adalah nilai bilangan ganjil yang nantinya akan ditampilkan pada listbox. Sebagai catatan, variabel input i tersebut boleh tidak berupa integer tapi berupa tipe data yang lain seperti string, char, double, float, byte, dsb.

Line 79 adalah handle untuk nilai i yang bukan bilangan ganjil. Urainnya hampir sama dengan kode blok di line 74, cuman di dalam kode else ini fungsi report progress hanya mengambil presentasi saja, karena jika i adalah bilangan maka kita tidak perlu menampilkan bilangan tersebut pada listboxt.

Line 84, thread dibuat sleep selama 13ms. Angka 13ms cuma coba-coba saja :D, silahkan gunakan angka yang lain sesuai dengan kebutuhan project yang dibuat. Yang perlu diperhatikan jika waktu sleep terlalu pendek maka updateGUI dapat mengalami masalah ketika mengupdate progress bar. Secara sederhana fungsi updateGUI butuh waktu beberapa milli sekon (mkn 12 - 17 ms tergantung tampilan GUI) untuk mengupdate GUI mainWindow, nah jika fungsi updateGUI tersebut belum selesai kemudian dia panggil lagi dari proses looping, berarti tar fungsi updateGUInya terlalu sibuk yang boleh jadi mengakibatkan aplikasi menjadi freeze. Makanya disini loopingnya di sleepkan dulu, biar fungsi updateGUI bisa selesai dengan tugasnya kemudian baru looping selanjutnya diproses :-). Nah itu kalo waktu sleepnya terlalu pendek, jika waktu sleep terlalu panjang otomatis update value diprogress bar terlihat agak lama dan membosankan, jadi pilih angka sleep yang pas untuk masing-masing aplikasi.

Line 87 - 91, ini adalah kode untuk mendeteksi sinyal cancel untuk menghentikan thread. Jika kembali melihat fungsi startButton_Click di line 36, disitu terdapat fungsi cancelAsync() yang telah dijelaskan sebelumnya bahwa fungsi cancelAsync tersebut berguna untuk memberikan sinyal untuk menghentikan thread background worker yang sedang berjalan. Nah sinyal dari cancelAsync ini diterima oleh fungsi cancellationPending yang menyebabkan e.cancel menjadi true (line 89), nilai true tersebut nantinya akan digunakan pada fungsi selesai() yang akan dijelaskan kemudian. Kemudian line 90, reportProgress diubah kembali menjadi nol, karena jelas thread ini harus dihentikan jadi progress barnya harus kembali di set ke nilai 0. Terus line 91, 'return', berarti fungsi threadProcess ini selesai yang mengakibatkan fungsi selesai() akan dijalankan dengan e.cancel bernilai true.

Line 97, terdapat fungsi ReportProgress kembali namun dengan nilai 100. Tentunya fungsi ini dapat dicapai jika proses looping telah selesai dan tidak ada sinyal untuk menghetikan thread, makanya nilainya 100. Kemudian line 98, e.Result = mBilGanjil, nah e.Result tersebut berarti menyimpan jumlah total bilangan ganjil yang dari selang 0 - args. e.Result ini akan digunakan oleh fungsi selesai() yang nantinya akan ditampilkan ke user. Kita lihat line 98 adalah kode terakhir dari fungsi threadProcess ini, berarti setelah itu fungsi selesai() akan dijalankan, namun dengan e.cancel = false.

Beralih ke fungsi updateGUI. Fungsi ini berguna untuk melakukan update terhadap item-item yang terdapat pada mainWindow aplikasi yang kita buat. Fungsi ini akan dijalankan ketika fungsi ReportProgress dieksekusi pada fungsi threadProcess. Seperti terlihat diatas, pada fungsi ReportProgress terdapat variabel input berupa presentasi dan nilai bilangan ganjil. Nah variabel-variabel tersebut akan digunakan lebih lanjut oleh updateGUI untuk menyesuaikan tampilan mainWindow yang lebih aktual.

Line 105, nilai progress bar diset sesuai dengan presentasi yang dimasukkan ke fungsi ReportProgress. Line 106 pun juga sama, cuman presentasinya ditampilkan pada label. Jadi selain progress bar yang terupdate kita juga dapat melihat presentasi progressnya.

Line 107, dilakukan pengecekan terhadap e.UserState. UserState sebenarnya menyimpan bilangan ganjil yang dimasukkan dari fungsi ReportProgress. Nah makanya disini dicek, kalo ada bilangan ganjil (e.UserState tidak bernilai 0), maka bilangan ganjil tersebut akan ditampilkan pada listboxt seperti yang dilakukan pada line 109.

Terakhir adalah fungsi selesai(). Seperti yang telah disebutkan sebelumnya, fungsi selesai() adalah fungsi yang baru akan dijalankan ketika fungsi threadProcess selesai atau eksekusi program keluar dari fungsi threadProcess. Sebagaimana diketahui, threadProcess diakhiri ketika ada perintah untuk menghentikan thread atau karena proses yang dikerjakan threadProcess (dalam hal ini mengecek dan menghitung bilangan ganjil) memang sudah selesai. Jadi dua kondisi tersebut akan dievaluasi di dalam fungsi selesai() ini.

Line 117, jika e.Cancelled bernilai true berarti menandakan bahwa fungsi threadProcess sebelumnya diakhiri karena adanya sinyal untuk menghentikan thread. Hal tersebut dapat dilihat pada line 89 di dalam fungsi threadProcess. Kemudian di line 119 - 134, kode programnya sama dengan line 34 - 59 yang mengambil bilangan inputan dari user kemudian dimasukkan ke variabel max yang kemudian dimasukkan kembali ke fungsi RunWorkerAsync(max){line 135} untuk memulai thread backgroundworker yang baru. Jadi secara sederhana, jika thread pertama di cancel maka thread kedua akan segera dijalankan sesaat setelah thread pertama berhenti tanpa menunggu user untuk mengklik tombol start. Nah makanya disini kita dapat menggunakan 1 tombol saja untuk menjalankan atau menghentikan thread yang sedang running.

Line 138, Di sini dideteksi jika fungsi threadProcess berhenti karena adanya error yang terjadi dalam sistem {error pada visual studio, error pada program, atw hardware pc, dsb...}. Jika ternyata error seperti ini terjadi maka akan dikeluarkan message seperti yang terlihat pada line 140.

Line 142 sampai terakhir adalah kode program yang akan dieksekusi jika fungsi threadProcess berhenti secara normal. Makanya di line 144 diperlihatkan jumlah bilangan ganjil yang telah dihitung. Jumlah bilangan ganjil tersebut diambil dari e.Result. Sebelumnya seperti terlihat pada line 98 di fungsi threadProcess, e.Result ini diassign mBilGanjil, sehingga pada fungsi selesai() nilai e.Result tersebut dapat digunakan kembali untuk ditampilkan ke user dengan menggunakan messageBox seperti pada line 144.

Nah sampai disini, kita telah membuat fungsi-fungsi yang nantinya digunakan untuk menjalankan backgroundworker sesuai dengan kebutuhan project yang sedang kita buat. Berikutnya adalah menghubungkan ketiga fungsi-fungsi diatas ke variabel worker. Untuk itu kembali ke fungsi public MainWindow() yang terletak dibaris-baris awal, kemudian tambahkan kode berikut :


public MainWindow() sebagaimana diketahui bersama adalah fungsi konstruktor, jadi didalam fungsi ini kita akan melakukan inialisasi variabel-variabel termasuk variabel worker yang telah dibuat. Line 28 adalah fungsi yang secara otomatis akan selalu ada karena digenerate secara otomatis oleh visual studio. Fungsi tersebut melakukan inisialisasi internal terhadap program kita seperti inisialisasi komponen-komponen pada file xml untuk GUI aplikasi. Kemudian line 30, variabel worker yang telah kita buat ditambahkan fitur reportprogress, Maksudnya worker ini dapat menggunakan fungsi ReportProgress yang telah dijelaskan sebelumya. Line 31, worker ditambahkan fitur yang dapat melakukan request untuk menghentikan thread. Jadi sekalipun didalam fungsi threadProcess terdapat kode untuk menghetikan thread, namun jika WorkerSupportCancellation tidak diset ke true, maka kode yang terdapat dalam fungsi threadProcess tersebut tidak akan berguna. Line 32, variabel worker diintegrasikan dengan fungsi threadProcess yang melakukan kegiatan utama dithread. Line 33, jika terdapat fungsi ReportProgress dari doWork, maka worker akan memanggil fungsi updateGUI, dan yang terakhir adalah jika workernya selesai maka fungsi selesa() akan dipanggil. So sampai disini kita bisa melihat semua fungsi-fungsi yang telah dibuat telah diintegrasikan. So... Jika programnya kita jalankan, hasilnya :
Kemudian pada textbox dimasukkan angka 678 terus tombol start ditekan hasilnya :
Nah ketika presentasi progress bar sekitar 58, angka pada textbox diganti, kemudian tombol start ditekan kembali sebelum presentasinya mencapai 100, maka progress bar akan start dari awal lagi. Jika kita kita tidak menggunakan kode untuk menghentikan thread backgroundworker yang sedang berjalan sekarang maka aplikasi ini akan membuat thread yang baru. So jika tombol start ditekan berulang-ulang, aplikasinya bisa freeze atau malah crash/not responding. Jadi terlihat, pentingnya untuk mengetahui teknik dalam menghentikan thread backgroundworker yang sedang running. :-)

Sekian...... semoga bermanfaat... :-)