Delphi RSS Resources, Delphi Components, Delphi Sites, Articles, Dynamic XML Feeds, Tutorials, Sources
 
 
 
Google
 
Web delphirss.com
| Server-Scripts.com | Informations for JAVA | Informations for PHP | SEO Web Links | Borland Delphi
 

Assembler

Write a byte to a specific adress
Caps Lock
Interrupt Service Routine


Write a byte to a specific adress

Question

Does anyone know how I can write a byte to a specific memory address
using Delphi?

Answer

A:
Delphi (and Borland Pascal in general) have buried in them an array
called  Port[].  All you have to do is address the bytes directly.  This
would write 0 to a port a 300 hex:

   Port[768] := 0;

Obviously you can use hex values too ($300 etc.)

I think there is also another array which I have not used called mem[] that
allows access to memory via segment and offset.  We played with this one to
write pixels to the DOS graphics screen.

A:
Here is the help section on Mem, MemW and MemL, right from Borland:

Object Pascal implements three predefined arrays which are used to directly
access memory.

Mem
	MemW
	MemL

Each component of Mem is a byte, each component of MemW is a Word, and each
component of MemL is a Longint.
The Mem arrays use a special syntax for indexes:

Two expressions of the integer type Word, separated by a colon, are used to
specify the segment base and offset of the memory location to access.
Here are two examples:

Mem[Seg0040:$0049] := 7;     {stores the value 7 in the byte at $0040:$0049}
Data := MemW[Seg(V):Ofs(V)]; {moves the Word value stored in the first 2
bytes of the variable V into the variable Data}

. . .

I just gave you the good news. The bad news is that Windows uses the 386
paging mechanism. This means that an address in software in segment:offset
pointer format is first converted to a 32 bit linear address. This linear
address is then converted to a physical address through the page tables in
the 386. The result is that the physical address in your custom board may or
may not be the same as the one seen by your Delphi program.

A:
The Mem[] function works perfectly fine. Remember that in Windows you
are operating in protected mode. Thus you are dealing with selectors
not segments. If you want to access memory at segment $E000, you have
to first create a selector for it. Once you have a selector, you can
access the segment with the Mem[] function.

Here is the code to obtain a selector for $E000 from DPMI.

  asm
    mov ax, 2
    mov bx, $E000
    int $31
    mov [SegE000],ax
  end;

  Data := mem[SegE000:0];


Caps Lock

Question

How to control caps lock key?

Answer

A:
In Windows enviroment, you can look at the keyboard lights values, but you can't
set it, because Windows intercept your peek in the memory and blocks it (I tryed
under Windows 95, maybe under Windows 3.11 it works). However, you should be able 
to look at the status.

Try to put this simple code in a function:

const
   SCROLLLOCK = 1;
   NUMLOCK    = 2;
   CAPSLOCK   = 4;

var
   Status:  Byte;
   PntK:    ^Byte;
begin
     PntK := Ptr($40, $97);		{directly point in memory}
     Status := Byte(PntK^);		{read the status}
     if (NUMLOCK and Status) = NUMLOCK then	{if NUM LOCK is on}
         Status := Status and (255 - NUMLOCK)	{turn it off}
     else
         Status := Status or 2;			{turn it on}
     Pntk^ := Status;				{poke in memory (don't works)}
end;

A:
I use this procedures to turn on the caps lock if it isn't already on when
the user enters my DBloockup combo.  This gets rid of the nasty problem
of case-sensitive indexes.

procedure TMainForm.StudentLookupEnter(Sender: TObject);
Var Level : Integer;
    KeyState : TKeyBoardState;
begin
  {check if caps-lock is on - if not turn it on}
  Level := GetKeyState(VK_CAPITAL);
  GetKeyboardState(KeyState);
  CapsLockStatus := KeyState;
  If Level = 0 then
    begin
      KeyState[VK_CAPITAL] := 1;
      setKeyboardState(KeyState);
    end;
end;

Interrupt Service Routine

Question

I am trying to write code which will install an interrupt service routine for
DOS interrupt 21H. I want my ISR to be called ANY time interrupt 21 is call
from any running program or the system itself.  Using the code below, I
don't seem to get any response at all.  I can't even get a GPF.
Any ideas, suggestions or pointers would be apreciated.

 procedure InitDOS21;
 begin
   PassCount := 0;
   GetIntVec($21, OldInt21);
   NewInt21 := @NewInt21ISR;
   SetIntVec($21, NewInt21);
 end;

 procedure ShutdownDOS21;
 begin
     Inc(PassCount);
     SetIntVec($21, OldInt21);
 end;

 procedure JmpOldISR(OldISR : Pointer);
 begin  { This procedure will jump from and ISR to the ISR vector passed.}
 			{ Taken from BREAKNOW.PAS. }
 	inline($5B/$58/$87/$5E/$0E/$87/$46/$10/$89/
   	$EC/$5D/$07/$1F/$5F/$5E/$5A/$59/$CB);
 end;

 procedure NewInt21ISR(Flags, CS, IP, AX, BX, CX, DX, SI,
      	DI ,DS, ES, BP: word);
 begin
     Inc(PassCount);
     { Do my processing }
     JmpOldISR( OldInt21);
 end;

Answer

A:
In TP6 and BP7 you needed to define your ISR like this:

procedure NewInt21ISR(...registers...); interrupt;

I've also seen people define them like this:

type
  IntRegisters = record
    case Byte of
      1 : (BP, ES, DS, DI, SI, DX, CX, BX, AX, IP, CS, Flags : Word);
      2 : (Dummy : Dummy5; DL, DH, CL, CH, BL, BH, AL, AH : Byte);
      end;

procedure NewInt21ISR(BP : WORD); interrupt;
var
  Regs : IntRegisters absolute BP;
begin
...
end;









© DelphiRSS.com. All Rights Reserved.