Personal BLOG Adnan Kasogi

SELAMAT DATANG DI BLOG ADNAN KASOGI

ELEKTRO UNAND ANGKATAN 23

2310952044--BLOG KULIAH

This is default featured slide 3 title

Go to Blogger edit html and find these sentences.Now replace these sentences with your own descriptions.

This is default featured slide 4 title

Go to Blogger edit html and find these sentences.Now replace these sentences with your own descriptions.

This is default featured slide 5 title

Go to Blogger edit html and find these sentences.Now replace these sentences with your own descriptions.

Selasa, 16 September 2025

Bab 8 CHAPTER 8 PROGRAMMING THE MICROPROCESSOR

 [KEMBALI KE MENU SEBELUMNYA]

Pendahuluan

    Bab ini membahas program dan teknik pemrograman dengan menggunakan inline assembler dari Visual C++ Express. Inline assembler Visual C++ sebenarnya sudah dijelaskan pada bab-bab sebelumnya, tetapi masih ada fitur-fitur lain yang bisa dipelajari di sini. Beberapa teknik pemrograman yang dibahas dalam bab ini antara lain:

  • Modul bahasa rakitan (assembly language modules)

  • Manipulasi keyboard dan tampilan layar

  • Modul program dan library files

  • Penggunaan mouse

  • Penggunaan timer

  • Teknik pemrograman penting lainnya

    Bab ini juga memberikan dasar pemrograman berharga agar program bisa dikembangkan dengan mudah di komputer pribadi menggunakan inline assembler, yang berfungsi sebagai landasan untuk aplikasi Visual C++ Express di Windows.


8–1 MODULAR PROGRAMMING[kembali]

    Pemrograman modular merupakan teknik yang digunakan ketika sebuah program terlalu besar untuk dikerjakan oleh satu orang. Dalam pendekatan ini, program dibagi ke dalam beberapa modul yang lebih kecil sehingga dapat dikembangkan secara terpisah dan kemudian digabungkan. Proses penggabungan modul-modul tersebut dilakukan oleh sebuah program bernama linker, yang sudah tersedia dalam Visual Studio. Linker berfungsi menyatukan berbagai object file hasil kompilasi atau assembly menjadi satu program yang lengkap. Selain melalui Visual Studio, proses linking juga dapat dijalankan lewat perintah pada command prompt Windows. Dalam praktiknya, konsep pemrograman modular juga melibatkan penggunaan file library serta deklarasi EXTRN dan PUBLIC untuk mengatur bagaimana suatu modul dapat diakses oleh modul lain.

The Assembler and Linker

    Assembler sendiri berperan mengubah kode sumber yang ditulis dalam bahasa assembly (biasanya berekstensi .ASM) menjadi sebuah object file berbentuk heksadesimal. Assembler ini merupakan bagian dari Visual Studio, misalnya dalam folder instalasi C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin. Sebagai contoh, sebuah file bernama NEW.ASM akan diproses oleh assembler dan menghasilkan file object. Namun perlu diperhatikan bahwa assembler bawaan Visual C++ tidak mendukung program 16-bit DOS. Untuk kebutuhan tersebut, digunakan assembler dan linker khusus yang bisa diperoleh dari Windows Driver Development Kit (DDK). Penulisan file sumber dapat dilakukan dengan editor teks sederhana seperti Notepad, selama file tersebut disimpan sebagai ASCII text.

EXAMPLE 8–1

C:\masm611\BIN\ml new.asm

Microsoft (R) Macro Assembler Version 6.11
Copyright (C) Microsoft Corp 1981-1993. All rights reserved.

Assembling: new.asm

Microsoft (R) Segmented Executable Linker Version 5.60.220 Sep 9 1994
Copyright (C) Microsoft Corp 1984-1993. All rights reserved.

Object Modules [.obj]: new.obj
Run File [new.exe]: new.exe
List File [nul.map]: nul
Libraries [.lib]:
Definitions File [nul.def]:

Assembler (ML) digunakan untuk membaca file sumber .asm dan menghasilkan file objek .obj. Pada tahap ini dapat pula dibuat file listing .lst untuk membantu analisis dan pemecahan masalah. Setelah itu, linker membaca file objek yang dihasilkan assembler dan menggabungkannya menjadi file eksekusi .exe, yang kemudian dapat dijalankan langsung melalui command prompt. Jika ukuran program cukup kecil (kurang dari 64K), file eksekusi dapat dikonversi menjadi file perintah .com, yang lebih sederhana dan memerlukan ruang disk lebih sedikit.

EXAMPLE 8–2

C:\masm611\BIN\ml new.asm what.asm donut.asm
Microsoft (R) Macro Assembler Version 6.11
Copyright (C) Microsoft Corp 1981-1993. All rights reserved.

    Assembling: new.asm
    Assembling: what.asm
    Assembling: donut.asm

Microsoft (R) Segmented Executable Linker Version 5.60.220 Sep 9 1994
Copyright (C) Microsoft Corp 1984-1993. All rights reserved.

Object Modules [.obj]: new.obj+
Object Modules [.obj]: what.obj+
Object Modules [.obj]: donut.obj
Run File [new.com]: new.com
List File [nul.map]: NUL
Libraries [.lib]:
Definitions File [nul.def]:

Pada contoh ini, assembler memproses tiga file sumber yaitu NEW.ASMWHAT.ASM, dan DONUT.ASM, lalu menghasilkan file objek masing-masing. Linker kemudian menggabungkan ketiga file objek tersebut menjadi satu file eksekusi dengan nama NEW.COM. Jika terdapat lebih dari satu file objek, file utama (misalnya NEW) harus diletakkan pertama, kemudian diikuti file pendukung lainnya. Selain itu, library tambahan dapat disertakan dengan perintah /LINK setelah nama program utama.

EXAMPLE 8–3

C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin>ml /c /Cx /coff new.asm
Microsoft (R) Macro Assembler Version 7.10.3077
Copyright (C) Microsoft Corporation. All rights reserved.

    Assembling: new.asm

Contoh ini memperlihatkan cara meng-assemble file NEW.ASM tanpa langsung melakukan linking. Perintah ml /c /Cx /coff digunakan agar assembler hanya menghasilkan file objek. Opsi /c berarti compile saja tanpa link, /Cx menjaga penulisan huruf besar/kecil pada fungsi dan variabel, sedangkan /coff menghasilkan format objek COFF (Common Object File Format) yang umum dipakai dalam lingkungan 32-bit dan kompatibel dengan Visual C++.



PUBLIC and EXTRN

    Dalam pemrograman assembly yang bersifat modular, komunikasi antar modul sangat penting agar program dapat diorganisasikan dengan baik. Dua direktif yang berperan utama dalam hal ini adalah PUBLIC dan EXTRN.

  • PUBLIC digunakan untuk mendeklarasikan label-label (baik berupa kode, data, maupun segmen) agar dapat diakses oleh modul lain. Dengan kata lain, label yang didefinisikan sebagai public dapat dilihat dan digunakan oleh program eksternal.

  • EXTRN (external) berfungsi sebaliknya, yaitu menyatakan bahwa label tertentu bersumber dari luar modul saat ini. Hal ini memungkinkan satu modul untuk memanggil fungsi atau menggunakan data dari modul lain yang telah mendeklarasikan labelnya sebagai PUBLIC.

    Tanpa kedua direktif ini, modul-modul tidak akan dapat saling berhubungan meskipun sudah dilink menjadi satu program. Dengan PUBLIC dan EXTRN, programmer dapat membagi program besar menjadi potongan lebih kecil (modular programming), membuatnya lebih terstruktur, mudah dikelola, dan dapat digunakan kembali.

EXAMPLE 8–4

.model flat, c
.data
    public Data1       ; declare Data1 public
    public Data2       ; declare Data2 public

Data1 db 100 dup(?)
Data2 db 100 dup(?)

.code
.startup
    public Read        ; declare Read public

Read proc far
    mov ah, 6

Contoh ini menunjukkan bagaimana direktif PUBLIC digunakan untuk membuat label dapat diakses modul lain. Variabel Data1 dan Data2 dideklarasikan sebagai public pada segmen data, sementara prosedur Read dideklarasikan sebagai public pada segmen kode. Dengan cara ini, modul eksternal yang terhubung dapat menggunakan data dan prosedur tersebut.

EXAMPLE 8–5

.model flat, c
.data
    extrn Data1:byte
    extrn Data2:byte
    extrn Data3:word
    extrn Data4:dword

.code
    extrn Read:far
.startup
    mov dx, offset Data1
    mov cx, 10
Start:
    call Read
    stosb
    loop Start
.exit
End

Contoh ini memperlihatkan bagaimana direktif EXTRN digunakan untuk menyatakan bahwa label tertentu berasal dari luar modul. Pada bagian .data, variabel Data1Data2Data3, dan Data4 didefinisikan sebagai eksternal dengan ukuran berbeda (BYTE, WORD, DWORD). Pada bagian .code, prosedur Read juga dideklarasikan sebagai eksternal dengan tipe FAR.

Instruksi program kemudian menggunakan data eksternal tersebut, seperti memindahkan alamat Data1 ke dalam register DX, melakukan loop, dan memanggil prosedur eksternal Read. Dengan begitu, modul ini hanya bisa berjalan bila dihubungkan dengan modul lain yang sudah mendeklarasikan label-label tersebut sebagai PUBLIC (contohnya pada Example 8–4).

LIBRARIES

    Library files adalah kumpulan prosedur yang digunakan oleh berbagai program. Prosedur-prosedur ini pertama kali ditulis dan kemudian dikompilasi ke dalam bentuk library file menggunakan program LIB.EXE yang menyertai MASM assembler. Library memungkinkan prosedur umum dikumpulkan dalam satu tempat sehingga dapat dipakai ulang oleh berbagai aplikasi, tanpa perlu ditulis ulang dari awal.

    Dalam praktiknya, library sering digunakan saat membangun modul bahasa assembly di Visual C++ (misalnya pada pembahasan Chapter 7 sebelumnya). Banyak library bawaan sudah tersedia dan dapat langsung dipanggil oleh linker menggunakan ekstensi .LIB. File library ini akan dipanggil secara otomatis ketika program melakukan proses linking dengan perintah linker.

    Alasan utama menggunakan library file adalah karena sifatnya yang menghemat waktu dan usaha. Alih-alih menyalin ulang kode prosedur ke setiap program, programmer cukup menyimpan fungsi-fungsi penting dalam sebuah library. Ketika program membutuhkan fungsi tertentu, linker hanya mengambil prosedur yang diperlukan dari library dan menambahkannya ke dalam hasil akhir program. Hal ini membuat pemrograman assembly menjadi lebih efisien, terstruktur, dan mudah dipelihara.


MEMBUAT LIBRARY ATAU PUSTAKA

Sebuah library file dapat dibuat dengan perintah LIB, yang secara internal mengeksekusi program LIB.EXE dari Visual Studio. Library file terdiri atas kumpulan file .OBJ hasil kompilasi assembler (atau bahasa lain) yang berisi prosedur atau fungsi. Dengan cara ini, sebuah fungsi dapat ditulis satu kali, dikompilasi menjadi object file, lalu dimasukkan ke dalam library agar dapat digunakan kembali oleh banyak program.

Contoh sederhana ditunjukkan dalam Example 8–6, di mana terdapat dua fungsi (UpperCase dan LowerCase) yang ditulis dalam sebuah modul assembly untuk kemudian dimasukkan ke library. Perlu diperhatikan bahwa setiap prosedur yang akan dimasukkan ke library harus diberi deklarasi PUBLIC, meskipun nama prosedurnya tidak harus sama dengan nama library. Selain itu, jika fungsi atau variabel eksternal dipanggil, tetap diperlukan deklarasi EXTRN pada masing-masing file.

Dengan cara ini, library file menjadi sarana yang sangat berguna untuk mengorganisasi kode, memudahkan pemanggilan ulang, serta memungkinkan integrasi langsung dengan program C++ atau bahasa tingkat tinggi lainnya.

EXAMPLE 8–6

.586
.model flat, c
.code
        public UpperCase
        public LowerCase

UpperCase proc ,\
        Data1:byte
        mov     al, Data1
        .if al >= 'a' && al <= 'z'
                sub al, 20h
        .endif
        ret
UpperCase endp

LowerCase proc ,\
        Data2:byte
        mov     al, Data2
        .if al >= 'A' && al <= 'Z'
                add al, 20h
        .endif
        ret
LowerCase endp
End
Pada contoh ini dibuat dua prosedur, yaitu UpperCase dan LowerCase, yang berfungsi untuk mengubah karakter huruf kecil menjadi huruf besar, serta huruf besar menjadi huruf kecil.

  • Prosedur UpperCase menerima sebuah karakter (Data1), kemudian dicek apakah termasuk huruf kecil ('a' sampai 'z'). Jika ya, maka nilai ASCII dikurangi 20h sehingga berubah menjadi huruf besar.

  • Prosedur LowerCase menerima karakter (Data2) dan memeriksa apakah termasuk huruf besar ('A' sampai 'Z'). Jika benar, nilainya ditambah 20h untuk menjadikannya huruf kecil.

  • Kedua prosedur ini dideklarasikan PUBLIC, sehingga bisa dimasukkan ke dalam library dan dipanggil oleh program lain.


EXAMPLE 8–7

protokol C++ (extern "C") yang diperlukan agar fungsi dalam file library bisa dipanggil dari program C++. Syaratnya: library tersebut harus di-link ke dalam program C++ tersebut.

extern "C" char UpperCase(char);
extern "C" char LowerCase(char);

Kode ini adalah deklarasi fungsi eksternal dalam C/C++.

  • extern "C" digunakan agar nama fungsi tidak diubah oleh compiler C++ (name mangling), sehingga bisa dipanggil dari assembly atau library eksternal.

  • UpperCase(char) akan mengubah karakter huruf kecil menjadi huruf besar.

  • LowerCase(char) akan mengubah karakter huruf besar menjadi huruf kecil.

EXAMPLE 8–8

Program LIB dimulai dengan menampilkan pesan copyright dari Microsoft, lalu dilanjutkan dengan prompt Library name.

  • Nama library yang dipilih pada contoh adalah CASE.LIB.

  • Karena ini adalah file library baru, program LIB meminta nama file objek (.OBJ) yang akan dimasukkan ke dalam library.

  • Sebelum menjalankan LIB, file assembly CASE.ASM harus terlebih dahulu di-assemble menggunakan ML (Microsoft Macro Assembler).

  • Perintah LIB yang sebenarnya dapat dilihat pada Example 8–8.

  • Perhatikan bahwa pada saat menjalankan LIB, nama object file harus dituliskan setelah nama perintah di command line.

C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin>lib case.obj

Microsoft (R) Library Manager Version 7.10.3077
Copyright (C) Microsoft Corporation. All rights reserved.

Penjelasan singkat:

  • Perintah lib case.obj digunakan untuk membuat file library (CASE.LIB) dari file objek case.obj yang sebelumnya dihasilkan oleh assembler (ml case.asm).

  • Library Manager dari Microsoft Visual Studio bertugas menggabungkan object file menjadi library yang nantinya bisa dipanggil oleh program lain.

EXAMPLE 8–9


Macros

Macro adalah sekumpulan instruksi yang menjalankan satu tugas, mirip seperti procedure yang juga hanya menjalankan satu tugas. Perbedaannya adalah procedure dipanggil menggunakan instruksi CALL, sedangkan macro (beserta semua instruksi di dalamnya) langsung dimasukkan ke dalam program pada titik di mana macro tersebut dipanggil.

Membuat macro mirip dengan membuat opcode baru, yaitu serangkaian instruksi yang bisa digunakan kembali di program. Kamu cukup menuliskan nama macro beserta parameter-parameter yang diperlukan, lalu assembler akan menggantikannya dengan instruksi yang sesuai di dalam program.

Karena tidak ada instruksi CALL atau RET, eksekusi macro biasanya lebih cepat dibanding procedure. Instruksi-instruksi dalam macro akan ditempatkan langsung di dalam program oleh assembler pada lokasi di mana macro dipanggil.

Namun perlu diperhatikan: macro tidak bisa dipakai di external assembly modules, hanya bisa berfungsi di dalam inline assembler.

Macro didefinisikan dengan arahan MACRO untuk membuka dan ENDM untuk menutup. Baris pertama macro berisi nama macro dan parameter-parameternya

EXAMPLE 8–10

Contoh 8–10 menunjukkan bagaimana sebuah macro dibuat dan digunakan dalam sebuah program. Enam baris pertama kode mendefinisikan macro. Macro ini memindahkan isi word (16-bit) dari lokasi memori B ke lokasi memori A. Setelah macro didefinisikan dalam contoh, macro tersebut dipanggil dua kali. Macro akan diperluas (expanded) oleh assembler sehingga Anda dapat melihat bagaimana macro diubah menjadi instruksi nyata untuk menghasilkan operasi pemindahan data.

Setiap pernyataan bahasa mesin heksadesimal yang diikuti oleh angka (1, dalam contoh ini) adalah hasil ekspansi macro. Pernyataan ekspansi tidak diketik dalam program sumber; ekspansi tersebut dihasilkan oleh assembler (jika .LSTALL dimasukkan dalam program) untuk menunjukkan bahwa assembler telah menambahkan instruksi tersebut ke dalam program.

Perhatikan bahwa komentar dalam macro diawali dengan ;; bukan ; seperti biasanya. Macro sequence selalu harus didefinisikan sebelum digunakan dalam program, sehingga biasanya diletakkan di bagian atas segmen kode.

;===========================
; Definisi Macro
;===========================
MOVE    MACRO A,B
        PUSH    AX
        MOV     AX,B
        MOV     A,AX
        POP     AX
ENDM

;===========================

; Ekspansi Macro oleh Assembler

;===========================

0000 50 PUSH AX

0001 A1 0002 R MOV AX,VAR2

0004 A3 0000 R MOV VAR1,AX

0007 58 POP AX

0008 50 PUSH AX

0009 A1 0006 R MOV AX,VAR4

000C A3 0004 R MOV VAR3,AX

000F 58 POP AX

EXAMPLE 8–11


;====================================
; Example 8-11: Local Variable in a Macro
;====================================

FILL    MACRO WHERE, HOW_MANY     ;; fill memory
        LOCAL FILL1
        PUSH    SI
        PUSH    CX
        MOV     SI,OFFSET WHERE
        MOV     CX,HOW_MANY
        MOV     AL,0
FILL1:  MOV     [SI],AL
        INC     SI
        LOOP    FILL1
        POP     CX
        POP     SI
ENDM

;====================================
; Pemanggilan Macro
;====================================
        FILL    MES1,5
        FILL    MES2,10
        

;====================================
; Ekspansi Assembler
;====================================
; Ekspansi untuk FILL MES1,5
0014  56              PUSH SI
0015  51              PUSH CX
0016  BE 0000 R       MOV SI,OFFSET MES1
0019  B9 0005         MOV CX,5
001C  B0 00           MOV AL,0
0020  88 04           ??0000: MOV [SI],AL
0022  46              INC SI
0023  E2 FB           LOOP ??0000
0025  59              POP CX
0026  5E              POP SI

; Ekspansi untuk FILL MES2,10
0030  56              PUSH SI
0031  51              PUSH CX
0032  BE 0014 R       MOV SI,OFFSET MES2
0035  B9 000A         MOV CX,10
0038  B0 00           MOV AL,0
003A  88 04           ??0001: MOV [SI],AL
003C  46              INC SI
003D  E2 FB           LOOP ??0001
003F  59              POP CX
0040  5E              POP SI

8–2 USING THE KEYBOARD AND VIDEO DISPLAY[kembali]

Reading the Keyboard


TABLE 8–1 The keyboard scanning and extended ASCII codes as returned from the keyboard.




FIGURE 8–1 Using the textbox with filtering.

EXAMPLE 8–12

private: System::Void Form1_Load(System::Objectˆ sender,
System::EventArgsˆ e)
{
       textBox1->Focus(); // set Focus to textbox1
}
bool keyHandled;
private: System::Void textBox1_KeyDown(System::Objectˆ sender,
    System::Windows::Forms::KeyEventArgsˆ e)
{   // this is called first
       keyHandled = true;
       if (e->KeyCode >= Keys::NumPad0 && e->KeyCode <= Keys::NumPad9 ||
            e->KeyCode >= Keys::D0 && e->KeyCode <= Keys::D9 &&
            e->Shift == false ||
            e->KeyCode >= Keys::A && e->KeyCode <= Keys::F ||
            e->KeyCode == Keys::Back)
    {
            keyHandled = false;
    }
}
private: System::Void textBox1_KeyPress(System::Objectˆ sender,
    System::Windows::Forms::KeyPressEventArgsˆ e)
{   // this is called second
    if (e->KeyChar >= ‘a’ && e->KeyChar <= ‘f’)
    {
        e->KeyChar -= 32; // make uppercase
    }
        e->Handled = keyHandled;
}

EXAMPLE 8–13


// Placed at the top of the program following the uses statements
int Filter(char key)
{
    int retval; // 0 = false, 1 = true
    _asm
    {
        mov eax,1
        cmp key,8 ; backspace
        jb good
        cmp key,30h
        jb bad
        cmp key,39h
        jbe good
        cmp key,41h
        jb bad
        cmp key,46h
        jbe good
        cmp key,61h
        jb bad
        cmp key,66h
        jbe good
        good: dec eax
        bad: mov retval,eax
}
return retval;
}
private: System::Void Form1_Load(System::Objectˆ sender,
    System::EventArgsˆ e)
    {
        textBox1->Focus();
    }
bool keyHandled;
// new version of textbox1_KeyDown
private: System::Void textBox1_KeyDown(System::Objectˆ sender,
    System::Windows::Forms::KeyEventArgsˆ e)
{
    keyHandled = Filter(e->KeyValue);
}
private: System::Void textBox1_KeyPress(System::Objectˆ sender,
    System::Windows::Forms::KeyPressEventArgsˆ e)
{
    if (e->KeyChar >= ‘a’ && e->KeyChar <= ‘f’)
    {
        e->KeyChar -= 32;
    }
    e->Handled = keyHandled;
}


FIGURE 8–2 Hexadecimal to decimal conversion.

Using the Video Display

EXAMPLE 8–14


private: System::Void textBox1_KeyPress(System::Objectˆ sender,
    System::Windows::Forms::KeyPressEventArgsˆ e)
{
    if (e->KeyChar >= ‘a’ && e->KeyChar <= ‘f’)
    {
        e->KeyChar -= 32;
    }
    else if (e->KeyChar == 13)
    {
        // software to display the decimal version in textBox2
        keyHandled = true;
    }
    e->Handled = keyHandled;
}

EXAMPLE 8–15


// placed after the using statements at the top of the program
int Filter(char key)
{
    int retval;
    _asm
    {
        mov eax,1
        cmp key,8 ; backspaceje good
        cmp key,30h         jb bad         cmp key,39h         jbe good         cmp key,41h         jb bad         cmp key,46h         jbe good         cmp key,61h         jb bad         cmp key,66h         jbe good
good:   dec a;
bad:    mov retval,eax
    }
    return retval;
}
int Converts(int number, short digit)
{
    _asm
    {
        mov eax,number
        shl eax,4
        mov dx,digit
        sub dx,30h
        cmp dx,9
        jbe later
        sub dx,7
later:         or al,dl
        mov number,eax
    }
    return number;
}
private: System::Void Form1_Load(System::Objectˆ sender,
    System::EventArgsˆ e)
{
    textBox1->Focus();
}
bool keyHandled;
private: System::Void textBox1_KeyDown(System::Objectˆ sender,
    System::Windows::Forms::KeyEventArgsˆ e)
{
    keyHandled = Filter(e->KeyValue);
}
private: System::Void textBox1_KeyPress(System::Objectˆ sender,
    System::Windows::Forms::KeyPressEventArgsˆ e)
{
    if (e->KeyChar >= ‘a’ && e->KeyChar <= ‘f’)
    {
        e->KeyChar -= 32;
    }
    else if (e->KeyChar == 13)
    {
        int number = 0;
        for (int a = 0; a < textBox1->Text->Length; a++)
        {
            number = Converts(number, textBox1->Text[a]);
        }
        textBox2->Text = Convert::ToString(number);
        keyHandled = true;
    }
    e->Handled = keyHandled;
}

Using a Timer in a Program

FIGURE 8–3 The Shift/ Rotate application design screen.

EXAMPLE 8–16


bool shift;
int count;
private: System::Void button1_Click(System::Objectˆ sender,
System::EventArgsˆ e)
{
  label1->Text = “Shifted”;
  label2->Text = “00011001”;
  shift = true;
  count = 8;
  timer1->Start();
}
private: System::Void button2_Click(System::Objectˆ sender,
System::EventArgsˆ e)
{
  label1->Text = “Rotated”;
  label2->Text = “00011001”;
  shift = false;
  count = 8;
  timer1->Start();
}
private: System::Void timer1_Tick(System::Objectˆ sender,
System::EventArgsˆ e)
{
  Stringˆ digit = “0”;
  if (shift == false && label2->Text[0] == ‘1’)
  {
  digit = “1”;
  }
  label2->Text = label2->Text->Remove(0,1) + digit;
  if (—count == 0)
  {
  timer1->Enabled = false;
  }
}

The Mouse

TABLE 8–2 Mouse message handlers.



FIGURE 8–4 Displaying the mouse coordinates.

Aplikasi ini menampilkan koordinat mouse pada dua label (label1 dan label2) dengan memanfaatkan event handler MouseMove yang membaca nilai X dan Y dari properti Location, lalu mengubahnya menjadi string menggunakan kelas Convert. Agar koordinat tetap terlacak ketika pointer berada di atas label, ditambahkan handler MouseMove khusus untuk label dengan penyesuaian (bias) pada nilai X dan Y. Bias ini diperoleh dari properti Location masing-masing label sesuai posisi label di form.


EXAMPLE 8–17


private: System::Void Form1_MouseMove(System::Objectˆ sender,
System::Windows::Forms::MouseEventArgsˆ e)
{
    label1->Text = “X-coordinate = ” + Convert::ToString(e->Location.X);
    label2->Text = “Y-coordinate = ” + Convert::ToString(e->Location.Y);
}

EXAMPLE 8–18


private: System::Void Form1_MouseMove(System::Objectˆ sender,
System::Windows::Forms::MouseEventArgsˆ ’e)
{
    label1->Text = “X-coordinate = ” + Convert::ToString(e->Location.X);
    label2->Text = “Y-coordinate = ” + Convert::ToString(e->Location.Y);
}
private: System::Void label1_MouseMove(System::Objectˆ sender,
System::Windows::Forms::MouseEventArgsˆ e)
{
    label1->Text = “X-coordinate = ” + Convert::ToString(e->Location.X+159);
    label2->Text = “Y-coordinate = ” + Convert::ToString(e->Location.Y+232);
}
private: System::Void label2_MouseMove(System::Objectˆ sender,
System::Windows::Forms::MouseEventArgsˆ e)
{
    label1->Text = “X-coordinate = ” + Convert::ToString(e->Location.X+159);
    label2->Text = “Y-coordinate = ” + Convert::ToString(e->Location.Y+246);
}

EXAMPLE 8–19


private: System::Void Form1_MouseDown(System::Objectˆ sender,
System::Windows::Forms::MouseEventArgsˆ e)
{
if (e->Button == ::mouses::MouseButtons::Left)
  {
  label1->ForeColor = Color::Red;
  label2->ForeColor = Color::Red;
  }
  else if (e->Button == ::mouses::MouseButtons::Right)
  {

  label1->ForeColor = Color::Blue;
  label2->ForeColor = Color::Blue;

  }
}

8–3 DATA CONVERSIONS [kembali]

Converting from Binary to ASCII

EXAMPLE 8–20


// place at top of program
// will not function in 64-bit mode
void ConvertAam(char number, char* data)
{
    _asm
    {
        mov ebx, data     ; pointer to ebx
        mov al, number    ; get test data
        mov ah, 0         ; clear AH
        aam               ; convert to BCD
        add ah, 20h
        cmp al, 20h       ; test for leading zero
        je D1             ; if leading zero
        add ah, 10h       ; convert to ASCII
    D1:
        mov [ebx], ah
        add al, 30h       ; convert to ASCII
        mov [ebx+1], al
    }
}

private: System::Void Form1_Load(System::Object^ sender,
                                System::EventArgs^ e)
{
    char temp[2]; // place for result
    ConvertAam(74, temp);

    Char a = temp[0];
    Char b = temp[1];

    label1->Text = Convert::ToString(a) + Convert::ToString(b);
}

EXAMPLE 8–21


void Converts(int number, int radix, char* data)
{
    _asm
    {
        mov ebx, data        ; initialize pointer
        push radix
        mov eax, number      ; get test data

    L1:
        mov edx, 0           ; clear edx
        div radix            ; divide by base
        push edx             ; save remainder
        cmp eax, 0
        jnz L1               ; repeat until 0

    L2:
        pop edx              ; get remainder
        cmp edx, radix
        je L4                ; if finished
        add dl, 30h          ; convert to ASCII
        cmp dl, 39h
        jbe L3
        add dl, 7

    L3:
        mov [ebx], dl        ; save digit
        inc ebx              ; point to next
        jmp L2               ; repeat until done

    L4:
        mov byte ptr [ebx], 0 ; save null in string
    }
}

private: System::Void Form1_Load(System::Object^ sender,
                                System::EventArgs^ e)
{
    char temp[32]; // place for result
    Converts(7423, 10, temp);

    String^ a = "";
    int count = 0;

    while (temp[count] != 0) // convert to string
    {
        Char b = temp[count++];
        a += b;
    }

    label1->Text = a;
}

Converting from ASCII to Binary

EXAMPLE 8–22


int ConvertAscii(char* data)
{
    int number = 0;
    _asm
    {
        mov ebx, data     ; initialize pointer
        mov ecx, 0

    B1:
        mov cl, [ebx]     ; get digit
        inc ebx           ; address next digit
        cmp cl, 0         ; if null found
        je B2
        sub cl, 30h       ; convert from ASCII to BCD
        mov eax, 10       ; multiply by 10
        mul number
        add eax, ecx      ; add digit
        mov number, eax   ; save result
        jmp B1

    B2:
    }
    return number;
}

private: System::Void Form1_Load(System::Object^ sender,
                                System::EventArgs^ e)
{
    char temp[] = "2316"; // string
    int number = ConvertAscii(temp);

    label1->Text = Convert::ToString(number);
}

Displaying and Reading Hexadecimal Data

EXAMPLE 8–23


unsigned char Conv(unsigned char temp)
{
    _asm
    {
        cmp temp, '9'
        jbe Conv2          ; if 0–9
        cmp temp, 'a'
        jb Conv1           ; if A–F
        sub temp, 20h      ; to uppercase

    Conv1:
        sub temp, 7

    Conv2:
        sub temp, 30h
    }
    return temp;
}

private: System::UInt32 ReadH(String^ temp)
{
    unsigned int numb = 0;

    for (int a = 0; a < temp->Length; a++)
    {
        numb <<= 4;              // shift 4 bits left (hex base)
        numb += Conv(temp[a]);   // add converted digit
    }

    return numb;
}

private: System::Void Form1_Load(System::Object^ sender,
                                System::EventArgs^ e)
{
    unsigned int temp = ReadH("2AB4");
    label1->Text = Convert::ToString(temp); // display in decimal
}

EXAMPLE 8–24


void Disph(unsigned int number, unsigned int size, char* temp)
{
    int a;

    number < i <<= (8 - size) * 4;   // adjust position

    for (a = 0; a < size; a++)
    {
        char temp1;

        _asm
        {
            rol number, 4
            mov al, byte ptr number
            and al, 0fh         ; make 0 – f
            add al, 30h         ; convert to ASCII
            cmp al, 39h
            jbe Disph1
            add al, 7

        Disph1:
            mov temp1, al
        }

        temp[a] = temp1; // add digit to string
    }

    temp[a] = 0; // null terminator
}

private: System::Void Form1_Load(System::Object^ sender,
                                System::EventArgs^ e)
{
    char temp[9];
    Disph(1000, 4, temp);

    String^ a = "";
    int count = 0;

    while (temp[count] != 0) // convert to string
    {
        Char b = temp[count++];
        a += b;
    }

    label1->Text = a;
}

Using Lookup Tables for Data Conversions

EXAMPLE 8–25

Lookup table sering dipakai untuk konversi data, yaitu dengan menyimpan daftar nilai di memori yang bisa diakses prosedur saat melakukan konversi. Instruksi XLAT biasanya digunakan untuk pencarian tabel jika data selebar 8-bit dan tabel tidak lebih dari 256 byte. Salah satu contoh penerapan adalah konversi BCD ke kode seven-segment. Contoh 8–25 menunjukkan tabel lookup berisi kode seven-segment untuk angka 0–9. Pada display seven-segment aktif-high (logika 1 menyalakan segmen), susunan bit dalam tabel diatur sehingga segmen a berada di posisi bit 0 dan segmen g di bit 6. Bit ke-7 bernilai 0, tetapi bisa digunakan untuk titik desimal jika diperlukan.


unsigned char LookUp(unsigned char temp)
{
    unsigned char temp1[] = {
        0x3f, 0x06, 0x5b, 0x4f, 0x66,
        0x6d, 0x7d, 0x07, 0x7f, 0x6f
    };

    _asm
    {
        lea ebx, temp1
        mov al, temp
        xlat
        mov temp, al
    }

    return temp;
}

FIGURE 8–5 The sevensegment display.

EXAMPLE 8–26

private: System::String^ GetDay(unsigned char day)
{
    array^ temp =
    {
        "Sunday",
        "Monday",
        "Tuesday",
        "Wednesday",
        "Thursday",
        "Friday",
        "Saturday",
    };

    return temp[day];
}

FIGURE 8–6 A sevensegment display.

An Example Program Using a Lookup Table

Program contoh pada Gambar 8–6 menampilkan karakter angka bergaya seven-segment dengan memanfaatkan lookup table. Input diperoleh dari keyboard menggunakan handler KeyDown dan KeyPress, lalu difilter agar hanya menerima angka 0–9. Setiap angka diubah menjadi kode seven-segment dan ditampilkan menggunakan panel control objects: panel horizontal berukuran 120×25 dan panel vertikal 25×75, dinamai panel1–panel7 sesuai urutan segmen. Latar belakang panel dibuat hitam, sedangkan fungsi Clear (Contoh 8–27) digunakan untuk menghapus tampilan angka dengan mengatur properti Visible dari panel, atau alternatifnya mengubah warna panel.

EXAMPLE 8–27


private: System::Void Clear()
{
    panel1->Visible = false;
    panel2->Visible = false;
    panel3->Visible = false;
    panel4->Visible = false;
    panel5->Visible = false;
    panel6->Visible = false;
    panel7->Visible = false;
}

EXAMPLE 8–28


private: System::Void Clear()
{
    panel1->Visible = false;
    panel2->Visible = false;
    panel3->Visible = false;
    panel4->Visible = false;
    panel5->Visible = false;
    panel6->Visible = false;
    panel7->Visible = false;
}

private: System::Void Form1_KeyDown(System::Object^ sender,
                                   System::Windows::Forms::KeyEventArgs^ e)
{
    char lookup[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66,
                     0x6d, 0x7d, 0x07, 0x7f, 0x6f};

    if (e->KeyCode >= Keys::D0 && e->KeyCode <= Keys::D9)
    {
        ShowDigit(lookup[e->KeyValue - 0x30]); // display the digit
    }
}

private: System::Void ShowDigit(unsigned char code)
{
    Clear();

    if ((code & 1)  == 1)  panel1->Visible = true; // segment a
    if ((code & 2)  == 2)  panel4->Visible = true; // segment b
    if ((code & 4)  == 4)  panel5->Visible = true; // segment c
    if ((code & 8)  == 8)  panel3->Visible = true; // segment d
    if ((code & 16) == 16) panel6->Visible = true; // segment e
    if ((code & 32) == 32) panel7->Visible = true; // segment f
    if ((code & 64) == 64) panel2->Visible = true; // segment g
}

private: System::Void Form1_Load(System::Object^ sender,
                                 System::EventArgs^ e)
{
    Clear();
}


8–4 DISK FILES [kembali]

Disk Organization

FIGURE 8–7 Structure of the disk.

FIGURE 8–8 Main data storage areas on a disk.

File Names

    File dan program disimpan di dalam disk dan diakses menggunakan nama file serta ekstensi dari nama file tersebut.
Pada sistem operasi DOS, nama file hanya boleh terdiri dari 1 hingga 8 karakter. Nama file dapat berisi hampir semua karakter ASCII, kecuali spasi atau karakter berikut:

\ . / [ ] * , : < > | ; ? =

    Selain nama file, file juga dapat memiliki ekstensi opsional yang panjangnya 1 sampai 3 karakter. Nama file dan ekstensi selalu dipisahkan dengan tanda titik (.).

    Jika menggunakan Windows 95 hingga Windows XP, nama file bisa memiliki panjang hingga 255 karakter dan bahkan dapat berisi spasi. Ini merupakan peningkatan dibandingkan batasan 8 karakter pada DOS. Selain itu, file pada Windows juga bisa memiliki lebih dari satu ekstensi.

Nama Direktori dan Subdirektori

    Sistem manajemen file pada DOS mengatur data dan program di dalam disk ke dalam direktori dan subdirektori.

    Pada Windows, direktori dan subdirektori disebut juga dengan file folder. Aturan yang berlaku pada nama file juga berlaku pada nama folder.

    Struktur disk dibuat sedemikian rupa sehingga ketika pertama kali diformat, disk sudah memiliki root directory. Root directory atau folder utama pada hard disk drive C dituliskan sebagai C:\. Folder lain dapat ditempatkan di dalam root directory.

FIGURE 8–9 Format of any FAT directory or subdirectory entry.

Sequential Access Files

Data pada disk disimpan dalam bentuk file, dengan struktur utama: boot sector, FAT (File Allocation Table) atau MFT (Master File Table), root directory, dan area data. Boot sector (512 byte) berisi bootstrap loader yang memuat OS ke RAM saat komputer dinyalakan. FAT/MFT menyimpan lokasi dan atribut file, sementara root directory (pada FAT) berisi daftar file dan subdirektori. Pada NTFS, informasi file disimpan dalam MFT record (1.024 byte) yang memuat nama, ukuran, atribut, tanggal, keamanan, hingga lokasi data (file run).

Nama file di DOS terbatas 1–8 karakter + ekstensi 1–3 karakter tanpa spasi, sedangkan di Windows bisa hingga 255 karakter dan boleh berisi spasi. Direktori diatur secara hierarkis (C:, C:\DATA, C:\DATA\AREA1, dst.). Semua file diakses secara sekuensial, dibaca/ditulis dari awal ke akhir.

FIGURE 8–10 A record in the Master File Table in the NTFS system.

EXAMPLE 8–29

Dalam C++/CLI, file dikelola dengan File class di namespace System::IO. File dibuat menggunakan metode Create, tetapi program harus mengecek apakah file sudah ada. Jika gagal dibuat (misalnya folder tidak ditemukan atau disk penuh), program menampilkan pesan error lewat message box. Contoh 8–29 menunjukkan implementasi pembuatan file dengan penanganan kesalahan ini.


String^ fileName = "C:\\Test.txt";

if (File::Exists(fileName) == false)
{
    // don’t forget using namespace System::IO;
    try
    {
        File::Create(fileName);
    }
    catch (...)
    {
        MessageBox::Show("Cannot create " + fileName);
        Application::Exit();
    }
}

// Test.txt now exists with a length of 0 bytes

EXAMPLE 8–30

Setelah sebuah file dibuat, langkah berikutnya adalah menulis data ke file. Penulisan dilakukan satu byte demi satu byte menggunakan FileStream class, yang selalu menulis mulai dari byte pertama file. Contoh 8–30 menunjukkan program yang membuat file Test1.txt di root directory dan mengisinya dengan 256 huruf A. Jika dibuka di Notepad, file akan penuh dengan huruf A. Setelah proses selesai, file stream wajib ditutup dengan fungsi Close(). Pada contoh ini, array byte dibuat dengan garbage collection class di C++ agar menjadi managed array, yang penting untuk pengelolaan memori otomatis.


String^ fileName = "C:\\Test1.txt";
array^ buffer = gcnew array(256);

try
{
    FileStream^ fs = File::OpenWrite(fileName);

    for (int a = 0; a < 256; a++)
    {
        buffer[a] = 'A';
    }

    fs->Write(buffer, 0, buffer->Length);
    fs->Close();
}
catch (...)
{
    MessageBox::Show("Disk error");
    Application::Exit();
}

EXAMPLE 8–31


int number = 0x20000;
array^ buf = gcnew array(4);

// C++ conversion
buf[0] = number;
buf[1] = number >> 8;
buf[2] = number >> 16;
buf[3] = number >> 24;

// Assembly language conversion
_asm
{
    mov eax, number
    mov buf[0], al
    mov buf[1], ah
    bswap eax     ; little endian to big endian
    mov buf[2], ah
    mov buf[3], al
}

EXAMPLE 8–32


String^ fileName = "C:\\Test1.txt";
array^ buffer1 = gcnew array(256);

try
{
    FileStream^ fs = File::OpenRead(fileName);
    fs->Read(buffer1, 0, 256);
    fs->Close();
}
catch (...)
{
    MessageBox::Show("Disk error");
    Application::Exit();
}

EXAMPLE 8–33


Stringˆ fileName = “C:\\Test1.txt”;
FileInfoˆ fi = gcnew FileInfo(fileName);
int fileLength = fi->Length;


FIGURE 8–11 The HexDump program.

EXAMPLE 8–34


EXAMPLE 8–35

Misalkan sebuah file sudah ada di dalam disk dan Anda harus menambahkan 256 byte informasi baru ke file tersebut.
Ketika file dibuka, pointer file akan menunjuk ke byte pertama dari file. Jika Anda mencoba menulis tanpa memindahkan pointer file ke akhir file, maka data baru akan menimpa 256 byte pertama dari file.

Contoh 8–35 menunjukkan urutan instruksi untuk Append, yaitu menambahkan 256 byte data ke akhir file, lalu menutup file tersebut. File ini ditambahkan dengan 256 byte data baru dari area Buffer.

String^ fileName = "C:\\Test1.txt";
array^ buffer = gcnew array(256);

try
{
    FileStream^ fs = File::OpenWrite(fileName);

    for (int a = 0; a < 256; a++)
    {
        buffer[a] = 'S';
    }

    fs->Seek(0, SeekOrigin::End);
    fs->Write(buffer, 0, buffer->Length);
    fs->Close();
}
catch (...)
{
    MessageBox::Show("Disk error");
    Application::Exit();
}

// or the same operation is performed using the offset number
// in the Write function as follows:

String^ fileName = "C:\\Test1.txt";
array^ buffer = gcnew array(256);

try
{
    FileStream^ fs = File::OpenWrite(fileName);

    for (int a = 0; a < 256; a++)
    {
        buffer[a] = 'S';
    }

    fs->Write(buffer, 256, buffer->Length);
    fs->Close();
}
catch (...)
{
    MessageBox::Show("Disk error");
    Application::Exit();
}

FIGURE 8–12 Inserting new data within an old file.

EXAMPLE 8–36

Contoh 8–36 menunjukkan sebuah program yang menyisipkan data baru ke dalam file lama.
Program ini menyalin file Data.new ke dalam file Data.old pada posisi setelah 256 byte pertama dari file Data.old.
Data baru dari buffer2 kemudian ditambahkan ke file, dan setelah itu diikuti oleh sisa isi file lama.
Fungsi-fungsi anggota baru dari File digunakan untuk menghapus file lama dan mengganti nama file baru agar menjadi nama file lama.


private: System::Void Form1_Load(System::Object^ sender,
                                 System::EventArgs^ e)
{
    String^ fileName1 = "C:\\Data.old";
    String^ fileName2 = "C:\\Data.new";
    int fileLength;

    array^ buffer1 = gcnew array(256);
    array^ buffer2 = gcnew array(6);

    try
    {
        FileStream^ fs1 = File::OpenWrite(fileName1);
        FileStream^ fs2 = File::OpenWrite(fileName2);

        FileInfo^ fi = gcnew FileInfo(fileName1);
        fileLength = fi->Length;

        fs1->Read(buffer1, 0, 256);
        fs2->Write(buffer1, 0, 256);
        fs2->Write(buffer2, 0, 6);

        fileLength -= 256;

        while (fileLength > 0)
        {
            fs1->Read(buffer1, 0, 256);
            fs2->Write(buffer1, 0, 256);
            fileLength -= 256;
        }

        fs1->Close();
        fs2->Close();
    }
    catch (...)
    {
        MessageBox::Show("Disk error");
        Application::Exit();
    }
}

Random Access Files

File akses acak (random access files) dikembangkan melalui perangkat lunak dengan menggunakan file akses berurutan (sequential access files).
Sebuah file akses acak diakses menggunakan nomor record, bukan dengan menelusuri file untuk mencari data.
Fungsi Seek menjadi sangat penting ketika file akses acak dibuat.
File akses acak jauh lebih mudah digunakan untuk volume data yang besar, yang sering disebut sebagai basis data (database).

Menyisipkan data di tengah file tidak bisa dilakukan langsung, sehingga diperlukan cara dengan membuat file baru. Caranya adalah menyalin bagian awal file lama sampai titik sisipan ke file baru, kemudian menambahkan data baru, lalu menyalin sisa isi file lama setelah titik sisipan. Setelah semua selesai, file lama dihapus dan file baru diubah namanya agar sama dengan file lama. Dengan metode ini, data baru dapat dimasukkan tanpa merusak struktur file yang sudah ada, seperti diperlihatkan pada contoh program yang menyalin isi setelah 256 byte, menyisipkan buffer baru, lalu menambahkan sisa isi file lama.

EXAMPLE 8–37

Contoh 8–37 menggambarkan sebuah program singkat yang membuat file bernama CUST.FIL dan memasukkan 5000 record kosong yang masing-masing berukuran 512 byte.
Sebuah record kosong berisi nilai 00H pada setiap byte.
File ini tampak cukup besar, tetapi sebenarnya masih muat di hard disk dengan kapasitas paling kecil sekalipun.


private: System::Void Form1_Load(System::Object^ sender,
                                 System::EventArgs^ e)
{
    String^ fileName = "C:\\Cust.fil";
    array^ buffer = gcnew array(512);

    // fill buffer
    for (int a = 0; a < 512; a++) 
    {
        buffer[a] = 0;
    }

    try
    {
        FileStream^ fs = File::OpenWrite(fileName);

        for (int a = 0; a < 5000; a++)
        {
            fs->Write(buffer, 0, 512);
        }

        fs->Close();
    }
    catch (...)
    {
        MessageBox::Show("Disk error");
        Application::Exit();
    }
}

EXAMPLE 8–38

Membaca dan menulis record pada random access file dilakukan dengan memanfaatkan fungsi Seek untuk langsung menuju lokasi record yang diinginkan. Karena setiap record memiliki ukuran tetap, misalnya 512 byte, maka nomor record dikalikan dengan 512 untuk mendapatkan posisi byte awal record tersebut. Contoh pada program (8–38) menunjukkan bahwa file CUST.FIL tetap terbuka sepanjang operasi, dan pointer file dipindahkan dari awal file ke lokasi record target. Dengan cara ini, proses membaca maupun menulis data bisa dilakukan secara cepat tanpa harus menelusuri isi file dari awal hingga posisi record.


void CCusDatabaseDlg::FindRecord(unsigned int RecordNumber)
{
    File.Seek(RecordNumber * 512, CFile::begin);
}

EXAMPLE 8–39

Fungsi-fungsi tambahan seperti WriteRecord, ReadRecord, FindLastNameRecord, dan FindBlankRecord digunakan untuk mempermudah pengelolaan database pelanggan dalam random access file. Fungsi WriteRecord bertugas menulis data baru ke dalam record tertentu, sedangkan ReadRecord membaca isi record berdasarkan nomor record. Fungsi FindLastNameRecord digunakan untuk mencari data pelanggan melalui pencocokan nama belakang, sementara FindBlankRecord berfungsi menemukan record kosong (berisi 00H) yang bisa dipakai untuk menambahkan data baru. Semua fungsi ini bekerja dengan memanfaatkan struktur data yang telah ditentukan untuk setiap record, sehingga akses, penyimpanan, maupun pencarian data dapat dilakukan secara teratur dan efisien.

^ FirstName = gcnew array(32);
    static array^ Mi        = gcnew array(1);
    static array^ LastName  = gcnew array(32);
    static array^ Street1   = gcnew array(64);
    static array^ Street2   = gcnew array(64);
    static array^ City      = gcnew array(32);
    static array^ State     = gcnew array(2);
    static array^ ZipCode   = gcnew array(9);
    static array^ Other     = gcnew array(276);
};

// functions placed at the end of the form1 class
static array^ buffer   = gcnew array(512);
static String^ fileName      = "C:\\Cust.fil";
static FileStream^ fs;
static Customer Record;

private: System::Void Form1_Load(System::Object^ sender,
                                 System::EventArgs^ e)
{
    // open the file when the application starts
    Customer Record;

    try
    {
        fs = File::OpenWrite(fileName);

        for (int a = 0; a < 5000; a++)
        {
            fs->Write(buffer, 0, 512);
        }

        fs->Close();
    }
    catch (...)
    {
        MessageBox::Show("Disk error");
        Application::Exit();
    }
}

private: System::Void FindRecord(unsigned int RecordNumber)
{
    fs->Seek(RecordNumber * 512, SeekOrigin::Begin);
}

private: System::Void WriteRecord(unsigned int RecordNumber)
{
    FindRecord(RecordNumber);

    fs->Write(Record.FirstName, 0, 32);
    fs->Write(Record.Mi,        0, 1);
    fs->Write(Record.LastName,  0, 32);
    fs->Write(Record.Street1,   0, 64);
    fs->Write(Record.Street2,   0, 64);
    fs->Write(Record.City,      0, 32);
    fs->Write(Record.State,     0, 2);
    fs->Write(Record.ZipCode,   0, 9);
}

private: System::Void ReadRecord(unsigned int RecordNumber)
{
    FindRecord(RecordNumber);

    fs->Read(Record.FirstName, 0, 32);
    fs->Read(Record.Mi,        0, 1);
    fs->Read(Record.LastName,  0, 32);
    fs->Read(Record.Street1,   0, 64);
    fs->Read(Record.Street2,   0, 64);
    fs->Read(Record.City,      0, 32);
    fs->Read(Record.State,     0, 2);
    fs->Read(Record.ZipCode,   0, 9);
}

private: System::UInt32 FindFirstName(array^ FirstName)
{
    for (int a = 0; a < 5000; a++)
    {
        ReadRecord(a);

        if (Record.FirstName == FirstName)
        {
            return a; // if found return record number
        }
    }

    return 5001; // if not found return 5001
}

private: System::UInt32 FindBlankRecord()
{
    for (int a = 0; a < 5000; a++)
    {
        ReadRecord(a);

        if (Record.LastName[0] == 0)
        {
            return a;
        }
    }

    return 0;
}

FIGURE 8–13 The DataTime application.