Every once in a while, you need to do something that seems simple but there doesn’t seem to be any way to do it. You search the help files and flip through the manuals but nothing’s there. It seems no one ever tried to do it before. One such problem is trying to change the modification date on a file. Seems simple doesn’t it? Just try to find something that mentions it. Well, there is a way to do it, but you have to go way back to the days before Windows and use something called a DOS Interrupt. Without going into a lot of detail, an interrupt is a way of telling the CPU that you want to do something. The CPU then accesses whatever program is associated with the particular interrupt and runs it.
Interrupts are divided into seven
categories:
struct WORDREGS {
Unions
C has something called unions that VB doesn’t have. Unions allow you to use one variable with
two or more different structures that point to the same data. The following statement creates
a new structure REGS containing both the WORDREGS and BYTEREGS structures:
Using int86x
int86x takes four arguments and has the following syntax:
int int86x(int, union REGS *, union REGS *, struct SREGS *);
The first argument is the interrupt to call which is always 33 (hex 21) for DOS functions.
The second argument is the initial register settings, the third is the variable to hold the
results of the call, and the fourth is the variable for the segment registers.
The function returns the same value contained in the ax register after the call. To use
int86x, you create variables to hold the initial and resulting values of the registers as
follows:
union REGS inregs, outregs;
Then a variable to hold the segment values:
struct SREGS segregs;
You’re then ready to start using int86x. The ChgTimeStamp function shows how to use int86x to set the time/date on a given file name. This function takes a file name, time, and date passed from VB.
int FAR PASCAL ChgTimeStamp(LPSTR fname, long ntime, long ndate) {
The VB declaration to call ChgTimeStamp follows:
Declare Function ChgTimeStamp% Lib "mydll.dll" (ByVal infile$, ByVal ntime&, Û
ByVal ndate&)
The file name variable is obvious but you probably wonder what form the ntime& and ndate&
variables take. The time is stored in a two-byte word and is based on the following formula:
Time = Hour ´ 2048 + Minutes ´ 32 + Seconds ¸ 2
A file created at 17:30:10 would be stored as the value 35781 (17 ´ 2048 + 30 ´ 32 + 10 ¸ 2 =
35781). So, if you want to change the file time to 11:30:12, you would set ntime to 23494
(11 ´ 2048 + 30 ´ 32 + 12 ¸ 2 = 23494). The time is stored in two-second intervals so you
can’t set the time to an odd value like 11:30:13. Since VB doesn’t have unsigned integers,
you need to use a long integer to store the time and date values.
The date is also stored in a two-byte word and is based on the following formula:
Date = (Year - 1980) ´ 512 + Month ´ 32 + Day
The DOS world starts January 1, 1980 and ends December 31, 2099. The date November 1, 1995 would be stored as 8033 ((1995 - 1980) ´ 512 + 11 ´ 32 + 1 = 8033). To change the date to February 2, 1985, you would set ndate to 2626 ((1985 - 1980) ´ 512 + 2 ´ 32 + 2 = 2626). The process to actually change the date requires that you open the file to get a file handle, then change the date and finally close it. To open the file takes DOS Function 61 (hex 3D). This function requires a variable to hold the file handle:
int ofile; /* variable to hold file handle */ and that you set the dx and ds registers to point to the file name string. Fortunately, there are two C macros to do this for you. FP_OFF and FP_SEG take a far pointer (fname) and converts it to its offset and segment components as follows: inregs.x.dx = FP_OFF(fname);The only possible error code is 6 (invalid handle). It’s not often that you need to use a DOS function call, but it’s nice to know how to do it if you need to. The VB Project CHNGDT.MAK shows how to use the C function ChgTimeStamp.
segregs.ds = FP_SEG(fname);
You can set the access mode but since we aren’t using the file, the access mode can be set to zero: segregs.es = 0; /* Access mode doesn't matter */
ah is used to hold the DOS function we want to call and the ax register holds the result of the call. The following statements open the file: inregs.h.ah = 0x3D; /* Open the file */
ofile = int86x( 0x21, &inregs, &outregs, &segregs);
if(outregs.x.cflag)
return(outregs.x.ax); /* return error code if file won't open */
The ax register is also used to return an error code so you need to check cflag to see if an error occurred. If cflag is non-zero then the possible error values in ax are 2 (file not found), 4 (file not found), 5 (access denied), or 12 (invalid access code). If no error occurred, we can then change the date using DOS function 87 (hex 57) as follows: inregs.h.ah = 0x57; /* Change the date */ inregs.h.al = 1; /* 0 = Get time, 1 = Set Time */ inregs.x.bx = ofile; /* File to open */ inregs.x.cx = (unsigned int)ntime; inregs.x.dx = (unsigned int)ndate; int86x( 0x21, &inregs, &outregs, &segregs); if(outregs.x.cflag) result = outregs.x.ax; /* return error code if date can't be changed */ al is used to either get or set the time, bx holds the file handle and cx and dx hold the time and date (they need to be converted to an unsigned integer). The possible error codes are 1 (invalid function¾caused if you set al to something other than 0 or 1) or 6 (invalid handle). Finally, all we need to do is close the file using DOS function 62 (hex 3E). The date/time change will not take affect unless the file is successfully closed. inregs.h.ah = 0x3E; /* Close the file */ int86x( 0x21, &inregs, &outregs, &segregs); if(outregs.x.cflag) return(outregs.x.ax); /* return error code if file can't be closed */ else return(result); /* return error or zero */
Click here to go back to the November '95 Article Index