Friday, February 24, 2006

ASM Using Debug to Find Video Card Manufacturer

I had someone point out this little tip to me. If you starting a machine from scratch and you need to find the model of the video card, you can use Debug to view the video bios to get the information you need. Simply run the following command from within Debug:

d c000:0

The manufacturer may not be evident on the first group that comes up. In that case, keep typing d and hit enter, eventually you will scroll down to the find manufacturer. Useful trick if you are on a Microsoft platform and you need to search for drivers. However, in the past I usually just throw in a bootable Linux Live-CD and view the /proc files to find the video card manufacturer, however that does not always work (although I have pretty good success using Knoppix).

ASM Hello World

I decided to do some more work with Assembly, and since I haven’t shown how to do a basic “Hello World” application, I decided I would (the graphical one I showed previously was a little too complex to qualify as Hello World). I will demonstrate two versions, one that uses DOS Interrupt 09, and another that will write directly to video memory (which I feel is much cooler than calling interrupts).

First, the easy one:
0BD0:0100 mov ah, 09
0BD0:0102 mov dx, 010C
0BD0:0105 int 21
0BD0:0107 mov ax, 4c00
0BD0:010A int 21
0BD0:010C db 'Hello World', '$'

This one is pretty basic. All it does is call the DOS interrupt with the memory address of the “Hello World” string in register DX. Then it exits back to DOS. The next program is a little more interesting:

0BD0:0100 mov si, 0119
0BD0:0103 mov di, 140
0BD0:0106 mov ax, b800
0BD0:0109 mov es, ax
0BD0:010B mov ah, 07
0BD0:010D mov cx, B
0BD0:0110 lodsb
0BD0:0111 stosw
0BD0:0112 loop 110
0BD0:0114 mov AX, 4c00
0BD0:0117 int 21
0BD0:0119 db 'Hello World'

First, we set the Source Index register with the location of the Hello World string, in this case at DS:0119 (remember, in Debug COM files, the Code Segment and Data Segment are set initially to the same location). We then set DI to 140h, which is a few lines down on the screen.

0BD0:0106 mov ax, b800
0BD0:0109 mov es, ax

Next we are setting AX to the location of the video memory. We then copy register AX to ES.  The reason for this is because we cannot access register ES directly, so we have to do it through one of the general purpose registers first, in this case AX.

0BD0:010B mov ah, 07

Here we set AH to the value of our character attribute information, which is a white text on a black background. Remember that in video memory, character information is stored in two bytes, the first being the character value, and the second being the attribute information. I stored the attribute information in the high order register since I will do a word move, and word moves reverse bytes. In other words, if AX is set to 0765, when I copy it to video memory, it gets copied as 6507.

0BD0:010D mov cx, B

This is setting up a loop that will run 11 times. 11 are the size of the string “Hello World”.

0BD0:0110 lodsb
0BD0:0111 stosw
0BD0:0112 loop 110

The first command loads a byte at location DS:SI into register AL. Now I have the word combination I will copy to video memory, so I use stosw to copy the entire AX register to the memory location pointed to by ES:DI. I then loop this from address 110. This loop will repeat 10 more times.

0BD0:0114 mov AX, 4c00
0BD0:0117 int 21

Exit to DOS.

0BD0:0119 db 'Hello World'

This defines the string “Hello World” starting at address 119.

The only drawback to this program is that the string prints in the same location on the screen every time you run it. I would recommend clearing the screen with the DOS Clear Screen command (cls). There are other options internal to the program itself, such as retrieving the cursor location, or clearing the screen itself. But this demonstrates how you can use lodsb/lodsw and stosb/stosw to quickly copy memory chunks between addresses.

Thursday, February 23, 2006

Why do we use Hexadecimal?

Thanks to OSNews.com for pointing out this site aimed at teaching C. While the site is still too new and the number of articles there are too few in number to really indicate if the authors efforts are worthwhile, but I enjoyed reading the articles and I feel he is heading in the right direction. However, whenever I come across a programming tutorial, I always find one thing glaringly omitted when talking about hexadecimal numbers. So much time is spent on how to work with them, but very rarely does anyone ever say why. And I find that strange. Its almost like your just expected to accept it, without any real knowledge as to why your working with a number system that is not the same as the number system that was crammed down your throat almost all your life.

The main reason why we use hexadecimal numbers is because it is much easier to express binary number representations in hex than it is in any other base number system. Computers do not actually work in hex (don’t laugh, beginning students do ask that question). Lets look at an example, using a byte. Bytes are typically 8 bits, and can store the values 0 – 255 (0000 0000 – 1111 1111 in binary). For people, expressing numbers in binary is not convenient. I am not going to turn around to my co-worker and tell him that my phone number is 101 101 101 001 010 001 010 for obvious reasons. Imaging having to try and work with that on a daily basis. So a more convenient expression is needed for the human side.

Since a byte is 8 bits, it makes sense to divide that up into two groups, the top 4 bits and the low 4 bits. Since 4 bits gives you the possible range from 0 – 15, a base 16 system is easier to work with, especially if you are only familiar with alphanumeric characters (I don’t know of any languages have 255 letters in their alphabet, but I am naive and not worldly). It’s easier to express a binary value to another person as “A” then it is to express it as “1010”. This way I can simple use 2 hex values to represent a byte and have it work cleanly. This way if I am piss poor at math, I only need to memorize the multiplication tables up to 15. So if I have a hex value of CE, I can easily determine that 12 * 14 = 206 in decimal, and can easily write it out in binary as 1100 1110. Trying to convert from binary would require me to know what each place holder represents, and add all the values together (128 + 64 + 8 + 4 + 2 = 206). It’s much easier to work with binary through hex than any other base system. Further reading available here.

Octal comes into a close second. In octal, you can represent, at most, 3 bits with a single octal digit. So its very easy to say 311 is 11 001 001. The problem with octal, as you can see, is that the 3rd octal digit can only goes as high as 3, so it does not represent a byte as cleanly as hex. Octal is used in Unix for permissions due to its 3-bit nature. If we take the three specific entitlements (read, write, execute) for a file, we find that it coincides very well with octal. That’s why you see those really funky “chmod 744” commands, because they are octal representation of permissions, 111 100 100, or R-W-E, Read, Read for owner, group, world respectively (at least that is how it was explained to me). The leftmost bit represents the read flag, the middle one represents the write flag, and the rightmost flag represents execute. So if you wanted the permission for read-write, it would be 110, or 6. Read and execute would be 101 or 5.

Incidentally, there is such a thing as a binary coded decimal. Binary coded decimals are used more for our convenience than for the machines. I have seen BCD more often in electronic circuits using 7 segment displays, and various encoding methods used in PC’s. In BCD, 4 bit patterns are used to represent one base 10 digit. Once the value 9 is represented, another 4 bits are allocated. To compare, the value 10 in straight binary is 1010, where as in BCD it is 0001 0000. Another example is in straight binary, 29 is represented as 0001 1101. In BCD it is 0010 1001.

Asm: Retrieve 3 Key Strokes And Display The Results

I have always been a big fan of assembly language. I miss the days of DOS where you could code little assembly applications and kind of grin at the prestige of being able to code in Assembler. A lot of people will give you all sorts of arguments as to why ASM is better than high level languages, or that there is no need for ASM anymore due to optimizing compilers, etc. I don’t really have a great technical argument for or against, I have just always liked assembly programming, and that’s not about to change. I have tried assembly programming both under Windows and Linux, but it’s just not the same as the good old days of DOS assembly programming. So I jumped at the chance to take an assembly course, although it is a little outdated material, if for nothing else than to work out the problems.

One of the problems I had to work on asked that we write a program that takes three characters from the keyboard, store them at location DS:200H, then output them using DOS interrupt 09H. They wanted it done in debug, and you would have to go back and edit the memory location at DS:204H to put in the necessary $ to terminate the string for the DOS interrupt. Balls to that I said, I prefer my programs to be standalone and able to be run from the command prompt. Below is the code for that program. To enter it and try it yourself, go to the DOS prompt and type in “debug keybrd1.com”, where keybrd1.com is the name of the COM file we will create for this program. Type in “a” and hit enter. Then enter the following code sequence below:

MOV     CX,0003
MOV     BX,0200
MOV     AH,10
INT     16
MOV     [BX],AL
INC     BX
LOOP    0106
MOV     AL,24
MOV     [BX],AL
MOV     AH,09
MOV     DX,0200
INT     21
MOV     AX,4C00
INT     21

Hit enter one more time. Then type in “r cx”. Once the prompt comes up, type “1F”. Then type “W”. You now have an executable COM file called keybrd1.com. Type “Q” to go back to the DOS prompt. Now run keybrd1.com. There are no prompts, so just hit 3 keys. They will be echoed back to you. Lets go through step-by-step how this program works.

MOV     CX,0003
MOV     BX,0200

These lines are initializing my registers for my internal loop. In this case, CX is storing the number of iterations the loop will run, and BX is storing the offset from DS to store the incoming characters. Since this is a COM program, the Stack Segment, Code Segment, Data Segment, and Extra Segment all reside in the same location, so we do not need to worry about Pushing or Popping those values.

MOV     AH,10
INT     16
MOV     [BX],AL

This is calling an interrupt to retrieve data from the keyboard. If there is no data ready, it will wait until a key is pressed. Once the interrupt is complete, the value of the key is stored in register AL. We then move that value to the memory location pointed to by register BX (which is why we have brackets around it).

INC     BX
LOOP    0106

We are now incrementing the BX register by 1 in order to point to the next memory location. By calling LOOP, we auto decrement CX by 1. If CX is zero, the next line is executed; otherwise we loop to the location indicated (in this case 106, or the MOV AH, 10 line).

MOV     AL,24
MOV     [BX],AL

This is doing some cleanup after out loop so that we can call the DOS interrupt for screen output. We are moving a “$” (ASCII value 24h) to the memory location just after our 3 stored key presses. BX is already pointing to this since we incremented on the last loop iteration.

MOV     AH,09
MOV     DX,0200
INT     21

Here, we are calling the DOS interrupt for screen output, using the string at DS:200h as the output, which is terminated by a “$”.

MOV     AX,4C00
INT     21

And now we are exiting the program and returning control to DOS. There is a lot going on here for a program that is only 38 Bytes. Although the equivalent program in C or C++ would be easier to understand and take less time and thought to code, there is just something cool about coding in ASM.

Of course, you could alternatively write the same program as follows:

-From DOS, type “debug keybrd1.com”
-Type “e CS:100”
-Enter “B9 03 00 BB 00 02 B4 10 CD 16 88 07 43 E2 F7 B0 24 88 07 B4 09 BA 00 02 CD 21 B8 00 4C CD 21”. Note the spaces between each Bytes. These are necessary. If you hit Enter, you will close out the memory edit mode in debug.
-Hit enter when you are done.
-Type “r CX”
-Type “1F”
-Type “w”
-Type “q”

This demonstrates entering programs as low level as possible without actually doing it in binary. Entering programs in this manner requires quite a bit of knowledge of the internal CPU instructions, how byte orders are swapped between memory and registers (“B8 00 4C” is moving the value of 4C00 to register AX, but is byte swapping 4C and 00).  

Thursday, February 16, 2006

Popup Windows Passing Data back to Parent Web Pages

Previously I had discussed building a simple fill in form and having it submit the results to a database using Coldfusion. Well, now I want to take this form one step further and have a lookup for the employees that will auto-fill their information into the form to help insure accuracy. While I can have them follow a wizard type sequence before going to the actual form, I feel that it is easier to have a small pop-up window appear when they click on a button, and have that window populate the parent form when the lookup is complete. It’s amazing that there is an actual legitimate use for pop-up windows besides insulting our consumer intelligence with obnoxious advertising of garbage that any intelligent individuals wouldn’t even consider buying.

Referencing my previous article, I have several fields for user related information. For the sake of this example, we will only focus on a few fields, the first name, last name, employee ID, and their job title. So that means I have a form that looks like so:

<form  id="horizontalForm" name="nomformpt1" method="post" action="nomination_form.cfm?Submit=1">
     <label for="lookupclass1">
<input name="emp_lookup" type="button"  id="emp_lookup" onClick="openWindow('lookup_employee.cfm','','width=425,height=150')" value="Lookup Employee Information">
         </label>
Name (First)
<input name="firstname" type="text" class="style3" id="firstname"  align="left" />
Name (Last)
<input name="lastname" type="text" class="style3" id="lastname" />
GEID#:
<input name="geid" type="text" class="style3" id="geid" size="10" maxlength="10">
Title/Position:
<input name="positiontitle" type="text" class="style3" id="positiontitle">

<input type="button"  class="blue" name="Submit" value="Submit Participant Info" onClick="submit()">
</form>

Notice the button “emp_lookup”. This button is going to open our lookup window, but not submit the form. It calls a Javascript action basically is a interface to the window.open() method. The actual function looks like so:

<script language="JavaScript" type="text/JavaScript">
<!--
function openWindow(theURL,winName,features) {
            var w = window.open(theURL,winName,features);
}
//-->
</script>

Now comes the pop-up page. This page is basically a Coldfusion page with a simple input box prompting the user to input their ID number. Once they do, it will perform a quick database lookup for the employee information, and then update the parent windows form with the correct information. This will use a similar mechanism as outlines last time, with the form calling the same page upon submission, but instead of inserting to a database, it will do the employee lookup, then create a small, blank HTML page with the Javascript to insert the returned values into parent pages form. I show the completed pop-up page in the following example. I removed all CSS and formatting tags, and replaced the query with a Coldfusion reference to a page containing the query itself.

<cfif not isdefined("form.no_emp")>
     <html>
     <head>
     <title>RDG National Training Nomination Form</title>
     <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
     </head>
          <body>
                   <form id="horizontalForm" action="lookup_employee.cfm?Submit=1" method="post">  
                         Look Up Employee Information by SOEID
                              Enter your SOEID: <input name="no_emp" type="text" class="style3" id="employeeinfo">
                              <input name="Submit" type="submit" class="blue2" value="Submit">
                    </form>
          </body>
     </html>         
<cfelse>
     <cfinclude template="qry_getEmployeeInfo.cfm">
     <html>
          <body>
               <cfif getEmployeeInfo.recordcount gt 0>
                    <cfoutput query="getEmployeeInfo">
                         <script>
                              window.opener.document.getElementById("firstname").value = '#fname#';
                              window.opener.document.getElementById("lastname").value = '#lname#';
                              window.opener.document.getElementById("geid").value = '#geid#';
                              window.opener.document.getElementById("positiontitle").value = '#jobtitle#';
                              
                              window.close();
                         </script>
                    </cfoutput>
               <cfelse>
                    No information found under that ID. Please check the ID number and try again.<br>
                    <a href="##" onClick="javascript:history.go(-1);">Back</a>
               </cfif>
          </body>
     </html>
</cfif>

There is not much to doing the pass back to the parent page. The key is using the window.opener property, which keeps the parent caller for any popup pages. The easiest way to get the data into the form fields is by using the document.getElementByID() method. Interestingly enough, I came across this IBM developerWorks article about AJAX, and they also mention how familiar a web developer should be with the getElementByID() method when working with the AJAX method.

With the lookup page completed, the user can click on the Lookup button, and have a quick means of filling out the form without having to type in the information. The full form has a lot more fields, which are prone to error, and the lookup for available classes is done in this manner as well. Being able to pass back data to a parent window from a pop-up window demonstrates that there are legitimate uses for those annoying pop-ups. Pop-up blockers do sometimes prevent this functionality from working. I’m going to look into using AJAX to have the form fill in automatically when the user puts in their ID on the form itself as opposed to the pop-up window.

Tuesday, February 14, 2006

ADO Data Control and Oracle Sequences

I came across an interesting problem that Google didn’t find a solution for. I have a small Visual Basic application that manages a small table that maps Perception Questionmark exams to Course Codes in Training Server 4.8. Very small table, however I need for the Exam Manager to manage this table since I don’t have the resources or time to dedicate to making changes for her. So I wrote this real small Visual Basic application to manage the table for her. The problem came when the OleDB Oracle driver began to mangle the large numbers used in one of the fields used to map to the Perception Session ID. Changing from the Oracle OleDB driver to an ODBC connection corrected that issue, however I had to manually create a primary key field based off of an auto-generating sequence. This really wouldn’t be an issue, except for two little problems. First, I am using the ADO Data Control, which does not auto-generate a new primary key, and second is that I cannot create a trigger to reside on the server due to policy restrictions set up by the DBA.

The solution I used is not necessarily elegant, but it did do the job without having to scrap what I had, keeping the same interface the user was already used to using, and solved the problem. Basically what I had to do is modify the ADO Data Controls WillMove and WillChangeRecord functions to call the Oracle Sequence and store in a hidden bound text control on the form.

The logic works like this. When the ADODC creates a new record, it will call the WillChangeRecord function, passing in the variable adReason set to adRsnAddNew. When the user fills in the bound text fields with the appropriate data, they can either hit the update button or use the ADODB to move, and the record will insert into the database. If they click on the Update button, this calls WillChangeRecord with adReason set to adRsnUpdate. If they click move, the function I want to focus on is the WillMove function. Both scenarios will do the same thing, have a custom code based ADO call to Oracles sequence to generate the next value and save it into the hidden text control for the key. However, I do not want to have this happen when update is called to modify an existing record. So what I do is create a global Boolean value that gets set when WillChangeRecord is called with adReason is set to adRsnAddNew. Once the update is complete, this flag gets set back to false. Below is the code demonstrating this.

'Crappy module wide flag determining if we are adding a new record
'if set, certain if branches will execute updateKeyValue function
'Module Scope within Form1
Dim needtoupdate As Boolean

‘Procedure to update the Form1.txtKey value to the next sequence value.
‘This textbox is bound to the primary key of the test map table
Private Sub updateKeyValue()
    'Store the new key generated from Oracle
    Dim mintNewKey As Integer
    
    'The three ADO components
    Dim com As ADODB.Command
    Dim con As ADODB.Connection
    Dim rs As ADODB.Recordset
    
    On Error GoTo ErrOnUpdate
    
    'Create new objects for the command and connection
    Set con = New ADODB.Connection
    Set com = New ADODB.Command

    'Use the same connection string as the ADO Data Control and open
    'the connection
    con.ConnectionString = Adodc1.ConnectionString
    con.CursorLocation = adUseClient
    con.Mode = adModeRead
    con.Open
        
    'Set up the active connection
    Set com.ActiveConnection = con
    com.CommandType = adCmdText
    com.CommandText = "select SEQ_TESTMAP.nextval from dual"
    
    'Execute the command and get the recordset
    Set rs = com.Execute
        
    'Store the new key value into the mintNewKey variable
    mintNewKey = rs("nextval").Value
    
    'Save this to the hidden bound text control on Form1
    Form1.txtKey.Text = mintNewKey
    
    'Reset the update flag to false
    needtoupdate = False
    
    'Free objects
    If Not (rs Is Nothing) Then
        Set rs = Nothing
    End If
    
    If Not (com Is Nothing) Then
        Set com = Nothing
    End If
    
    If Not (con Is Nothing) Then
        If con.State = ADODB.adStateOpen Then
            con.Close
        End If
        
        Set con = Nothing
    End If
    
    Exit Sub
ErrOnUpdate:
    If Not (rs Is Nothing) Then
        Set rs = Nothing
    End If
    
    If Not (com Is Nothing) Then
        Set com = Nothing
    End If
    
    If Not (con Is Nothing) Then
        If con.State = ADODB.adStateOpen Then
            con.Close
        End If
        
        Set con = Nothing
    End If
    
    MsgBox "There was an error updating the database: " & vbNewLine & Err.Number & " - " & Err.Description, vbCritical, "Error"
End Sub

Private Sub Adodc1_WillChangeRecord(ByVal adReason As ADODB.EventReasonEnum, ByVal cRecords As Long, adStatus As ADODB.EventStatusEnum, ByVal pRecordset As ADODB.Recordset)
    'If the new record has already been inserted, this function was called
    'to issue and update, and the update flag is set, then call the
    'update key value function
    If (adReason = adRsnUpdate) And (needtoupdate) Then
        updateKeyValue
    End If
    
    'If we are creating a new record, set the need to update flag to true
    If (adReason = adRsnAddNew) Then
        needtoupdate = True
    End If
End Sub

Private Sub Adodc1_WillMove(ByVal adReason As ADODB.EventReasonEnum, adStatus As ADODB.EventStatusEnum, ByVal pRecordset As ADODB.Recordset)
    If (needtoupdate) Then
        updateKeyValue
    End If
End Sub

Typically I never use the ADO Data Control for this very reason, however time constraints and drive prevented me from hand coding all the controls for navigating through he recordset, and despite this one hurdle, using the ADO Data Control was relatively painless. While I have worked with similar components in Delphi in the past, which were much more robust in my opinion, for the task at hand this was sufficient. Had triggers been allowed, this would have been a simple matter to address on the backend. However the constraints of the operating environment did not allow for this, so I had to adapt the solution to the client side. I had to admit surprise at not finding a solution online. Perhaps it was on a VB forum somewhere and the thread has been depreciated and archived. Once .Net gets pushed out as SOE here, I can finally retire VB6, and I hate to admit it, but I will be sad to see it go. I will have to do more research into why the Oracle OleDB driver mangled those large numbers, that seems really strange.