This lesson is a continuation of the previous program. ( attrib.exw ) Attrib2.exw will allow you to type any program name into it's EditText entry box to get and set a file's attribute bits. It will also allow you to update the last-write time of the file, in the same way that the old DOS program, TOUCH.EXE did, using the current system time.
This lesson also introduces a few more DLL functions not in win32lib.ew yet.
The FindFirstFile( ) function queries a file, and returns some information about that file in a block of allocated memory. Since one of the elements in this structure is the file size, we no longer have to use GetFileSize( ), as we did in the previous lesson. This structure also contains information about the file's attributes, creation time, and the last-access and last-write times.
Since win32 handles file times in coordinated universal time, ( good grief ! ), to handle different time zones, we use FileTimeToLocalFileTime( ) to do a little 'time travelling', to our local time.
FileTimeToSystemTime( ) translates the 64 bit file time into the format described for the SystemTime structure, which uses 16 bits for each of eight time elements.
GetSystemTimeAsFileTime( ) simply does the reverse, converting from eight 16 bit elements, to the 64 bit value used in files.
Finally, SetFileTime( ) actually 'touches' the file, to update it's last-write time.
--
attrib2.exw
--attrib2.exw--
--start code--
include win32lib.ew
without warning
sequence file_name
-- for demonstration, pre-set a file name
file_name="attrib2.exw"
atom junk, file_id_ptr, file_handle
--declare some strings as constants
constant
str1 = "file size = ",
str2 = "current attributes = ",
str3 = "long filename = ",
str4 = "short filename = ",
str5 = "filedate ( m/d/y ) = ",
str6 = "filetime ( last modified ) = ",
--declare some constant values by name
zOPEN_EXISTING = 3,
zGENERIC_WRITE = #40000000,
zMAX_PATH = 260,
zFILE_ATTRIBUTE_READONLY = 1,
zFILE_ATTRIBUTE_HIDDEN = 2,
zFILE_ATTRIBUTE_ARCHIVE = 32,
zFILE_ATTRIBUTE_NORMAL = 128,
--create our window and all it's controls
Win = create( Window, "File Attributes", 0, 0, 0, 285, 365, 0 ),
Label0 = create( LText, "filename:", Win, 10, 12, 70, 20, 0 ),
Entry = create( EditText, "", Win, 75, 10, 190, 20, 0 ),
Label1 = create( LText, "", Win, 10, 40, 180, 20, 0 ),
Label2 = create( LText, "", Win, 10, 65, 180, 20, 0 ),
Label3 = create( LText, "", Win, 10, 200, 290, 20, 0 ),
Label4 = create( LText, "", Win, 10, 225, 290, 20, 0 ),
Label5 = create( LText, "", Win, 10, 250, 290, 20, 0 ),
Label6 = create( LText, "", Win, 10, 275, 290, 20, 0 ),
Check1 = create( CheckBox, " Read-Only ( 1 )", Win, 10, 90, 170, 20, 0 ),
Check2 = create( CheckBox, " Hidden ( 2 )", Win, 10, 115, 170, 20, 0 ),
Check3 = create( CheckBox, " Archive ( 32 )", Win, 10, 140, 170, 20, 0 ),
Button1 = create( PushButton, "Change Attributes", Win, 10, 165, 130, 25, 0 ),
Button2 = create( PushButton, "Update FileTime", Win, 10, 300, 130, 25, 0 ),
--**
--declare all our 'links' to the DLL functions
zGetFileAttributes=registerw32Function( kernel32, "GetFileAttributesA", {C_POINTER}, C_LONG ),
zSetFileAttributes=registerw32Function( kernel32, "SetFileAttributesA", {C_POINTER, C_LONG}, C_LONG ),
zFindFirstFile = registerw32Function( kernel32, "FindFirstFileA", {C_POINTER, C_POINTER}, C_LONG ),
zFileTimeToLocalFileTime = registerw32Function( kernel32, "FileTimeToLocalFileTime", {C_POINTER, C_POINTER}, C_LONG ),
zFileTimeToSystemTime = registerw32Function( kernel32, "FileTimeToSystemTime", {C_POINTER, C_POINTER}, C_LONG ),
zGetSystemTimeAsFileTime = registerw32Procedure( kernel32, "GetSystemTimeAsFileTime", {C_POINTER} ),
zSetFileTime = registerw32Function( kernel32, "SetFileTime", {C_LONG, C_POINTER, C_POINTER, C_POINTER}, C_LONG ),
zCreateFile = registerw32Function( kernel32, "CreateFileA",
{C_POINTER, C_LONG, C_LONG, C_LONG, C_LONG, C_LONG, C_LONG}, C_LONG ),
zCloseHandle = registerw32Function( kernel32, "CloseHandle", {C_LONG}, C_LONG ),
--declare and 'allocate' all our structures
-- LastWriteTemp structure
size_of_LastWriteTemp = 8,
Local=allocate( size_of_LastWriteTemp ),
LowLocalTime = Local + 0,
HighLocalTime = Local + 4,
-- WIN32_FIND_DATA structure
size_of_WIN32_FIND_DATA = 318,
file_data=allocate( size_of_WIN32_FIND_DATA ),
dwFileAttributes = file_data + 0,
ftCreationTime = file_data + 4,
ftLastAccessTime = file_data + 12,
ftLastWriteTime = file_data + 20,
nFileSizeHigh = file_data + 28,
nFileSizeLow = file_data + 32,
dwReserved0 = file_data + 36,
dwReserved1 = file_data + 40,
cFileName = file_data + 44,
cAlternateFileName = cFileName + zMAX_PATH,
-- SystemTime structure
size_of_SystemTime = 16,
Time=allocate( size_of_SystemTime ),
wYear = Time + 0,
wMonth = Time + 2,
wDayOfWeek = Time + 4,
wDay = Time + 6,
wHour= Time + 8,
wMinute = Time + 10,
wSecond = Time + 12,
wMilliseconds = Time + 14
--set the font for the check-box labels to 'fixed'
--so everything stays lined up.
for i=Check1 to Check3 do
setFont( i, "Courier New", 10, 1 )
end for
--give our window background some color
setWindowBackColor( Win, rgb( 255, 255, 0 ) )
--do our 'time-travelling'.
procedure show_file_time()
sequence t_string
junk=w32Func( zFileTimeToLocalFileTime, {ftLastWriteTime, Local} )
junk=w32Func( zFileTimeToSystemTime, {Local, Time} )
t_string=sprintf( "%d", peek( wMonth ) ) & "/"
& sprintf( "%d", peek( wDay ) ) & "/"
--the year is four digits in two bytes
& sprintf( "%d", peek( wYear )+( peek( wYear+1 )*256 ) )
setText( Label5, str5 & sprintf( "%s", {t_string} ) )
t_string=sprintf( "%2d", peek( wHour ) ) & ":"
--always express minutes as two digits
& sprintf( "%02d", peek( wMinute ) )
setText( Label6, str6 & sprintf( "%s", {t_string} ) )
end procedure
--'touch' our file, to set current time.
procedure set_file_time( )
file_handle=w32Func( zCreateFile,
{file_id_ptr, zGENERIC_WRITE, 0, 0, zOPEN_EXISTING, 0, 0} )
w32Proc( zGetSystemTimeAsFileTime, {Local} )
junk=w32Func( zSetFileTime, {file_handle, NULL, NULL, Local} )
junk=w32Func( zCloseHandle, {file_handle} )
junk=w32Func( zFindFirstFile, {file_id_ptr, file_data} )
show_file_time( )
end procedure
--fetch the file's information
--and display it.
procedure do_it(atom self, atom event, sequence params)
setText( Entry, file_name )
file_id_ptr=allocate_string( file_name )
file_handle=w32Func( zCreateFile,
{file_id_ptr, 0, 0, 0, zOPEN_EXISTING, 0, 0} )
--does this file exist ?
if file_handle != -1 then
junk=w32Func( zFindFirstFile, {file_id_ptr, file_data} )
setText( Label1, str1 & sprintf( "%d", peek4u( nFileSizeLow ) ) )
junk=peek4u( dwFileAttributes )
setText( Label2, str2 & sprintf( "%d", junk ) )
if junk < zFILE_ATTRIBUTE_NORMAL then
if junk >= zFILE_ATTRIBUTE_ARCHIVE then
setCheck( Check3, 1 ) junk=junk-zFILE_ATTRIBUTE_ARCHIVE
end if
if junk >= zFILE_ATTRIBUTE_HIDDEN then
setCheck( Check2, 1 ) junk=junk-zFILE_ATTRIBUTE_HIDDEN
end if
if junk = zFILE_ATTRIBUTE_READONLY then
setCheck( Check1, 1 )
end if
end if
setText( Label3, str3 & sprintf( "%s", {peek_string( cFileName )} ) )
setText( Label4, str4 & sprintf( "%s", {peek_string( cAlternateFileName )} ) )
show_file_time( )
--If NO SUCH FILE, clean up the mess,
else
setText( Label1, str1 ) setText( Label2, str2 ) setText( Label3, str3 )
setText( Label4, str4 ) setText( Label5, str5 ) setText( Label6, str6 )
--and tell the user.
junk = message_box( "NO SUCH FILE", "ERROR !", #2000 )
end if
junk=w32Func( zCloseHandle, {file_handle} )
end procedure
--update the file's attribute flags
procedure set_attribs(atom self, atom event, sequence params)
atom attribs
attribs=0
if isChecked( Check1 ) then attribs=attribs+1 end if
if isChecked( Check2 ) then attribs=attribs+2 end if
if isChecked( Check3 ) then attribs=attribs+32 end if
junk=w32Func( zSetFileAttributes, {file_id_ptr, attribs} )
junk=w32Func( zGetFileAttributes, {file_id_ptr} )
setText( Label2, str2 & sprintf( "%d", junk ) )
end procedure
--remove leading spaces, just in case !
function trim_left( sequence x )
for i=1 to length( x ) do
if x[i] != ' ' then return x[i..length( x )] end if
end for
return {}
end function
--if user hits the enter key, look for new file
procedure new_name( )
setCheck( Check1, 0 ) setCheck( Check2, 0 ) setCheck( Check3, 0 )
file_name=getText( Entry )
file_name=trim_left( file_name )
do_it(1,2,"") -- arbitrary params
end procedure
procedure onkey_entry(atom self, atom event, sequence params)
integer key key = params[1]
if key=13 then new_name( ) end if
end procedure
setHandler( Win, w32HOpen, routine_id("do_it") )
setHandler( Button1, w32HClick, routine_id("set_attribs") )
setHandler( Button2, w32HClick, routine_id("set_file_time") )
setHandler( Entry, w32HKeyDown, routine_id("onkey_entry") )
WinMain( Win, Normal )
--end code--This program only handles file sizes up to 32 bits. I'll just leave it this way, for you to 'fix'.
...about structures.
Or really late at night, pointers to variables accessed through 'shared' allocated memory accessible to both Euphoria, and Win32 DLL's ... ;- )
Please note that I have declared my 'structure' constants in this program a little differently.
One can declare the WIN32_FIND_DATA structure in the usual way as:
constant
dwFileAttributes = 0,
ftCreationTime = 4,
ftLastAccessTime = 12,
ftLastWriteTime = 20,
nFileSizeHigh = 28,
...etc:...and then allocate the required space with:
file_data = allocate( 318 )
However, since we are actually only declaring the offsets into the structure, we have to access it with a 'calculation' statement like:
xyz = peek( file_data + nFileSizeHigh ) ...to access the fifth element in the structure.
By declaring it 'backwards' to the above, one creates named constants which can be used with a little less effort.
constant
file_data = allocate( 318 ),
dwFileAttributes = file_data + 0,
ftCreationTime = file_data + 4,
ftLastAccessTime = file_data + 12,
ftLastWriteTime = file_data + 20,
nFileSizeHigh = file_data + 28,
...etc:
xyz = peek( nFileSizeHigh )
...to access the fifth element in the structure.
This works just fine, as long as one doesn't ( free( file_data ) ) in the middle of the program's execution, because it, and all pointers to it, were declared as constants.
...end...