...very carefully !
First, a little WARNING !
Trying to access Windows DLL's, especially those that perform an operation on your file system, can be hazardous to both your health and the health of your computer, so if you aren't sure of what you are doing, don't !
In this lesson I am going to try and illustrate how one can access some of the simple functions in kernel32.dll. This DLL is just a library of routines which the programmer can use in his own programs. Since the standard Windows DLL's are all written in C, we have to write a 'wrapper' for each of the functions we are trying to use, which links our EUPHORIA program to these C functions, and the information they return.
Most of these C functions return a value, or set of values, by giving the C function a memory POINTER to the desired location of these values. We create the block of memory where we want our information stored, by using the allocate() function, which reserves a block of memory for our use, and returns a value which points to that block of memory. We can use this POINTER to retrieve the information we want, by using the peek() functions in EUPHORIA.
The first kernel32.dll function our program will access is the GlobalMemoryStatus function. It is described in the Win32 Programmers Reference in the following way, using C programming syntax.
( ..first, it's definition.. )
The GlobalMemoryStatus function retrieves information about current
available memory. The function returns information about both physical
and virtual memory.
( ..then, the actual 'C' lingo..)
VOID GlobalMemoryStatus(
LPMEMORYSTATUS lpBuffer // pointer to the memory status structure
);
( ..then, the information it requires.. )
Parameters
lpBuffer
Points to a MEMORYSTATUS structure in which information about current
memory availability is returned. Before calling this function, the calling
process should set the dwLength member of this structure.
( ..and the MEMORYSTATUS structure is defined as:.. )
typedef struct _MEMORYSTATUS { // mst
DWORD dwLength; // sizeof(MEMORYSTATUS)
DWORD dwMemoryLoad; // percent of memory in use
DWORD dwTotalPhys; // bytes of physical memory
DWORD dwAvailPhys; // free physical memory bytes
DWORD dwTotalPageFile; // bytes of paging file
DWORD dwAvailPageFile; // free bytes of paging file
DWORD dwTotalVirtual; // user bytes of address space
DWORD dwAvailVirtual; // free user bytes
} MEMORYSTATUS, *LPMEMORYSTATUS;All this really means, since a DWORD is 4 bytes, and there are 8 of them, is that we have to allocate 32 bytes for our structure, and 'poke' the size of that structure into the first 4 bytes of that structure, before calling the function.
Since GlobalMemoryStatus is really a procedure, and does not return a value, ( as indicated by the VOID reference in its description ), we have to call it with w32Proc(), being sure to give it a pointer to our allocated memory block.
When the function returns, the allocated block of memory will contain the specified information, in 4 byte chunks. We can access this with the EUPHORIA peek4u() function, and place the data into a sequence. Once this is done, we can then return the allocated memory to the system with free().
The following demo program gets the Windows memory information in it's GetMemory() procedure. Please note that the percentage of memory displayed also includes the available memory in the Windows 'cache' at the time, which for most systems, is a variable size, created by Windows 'on-the-fly'.
Since we're at it, I'm also
going to get the path of your Windows directory, the path of this
program, and the current time, by calling three more functions in
kernel32.dll.
These routines are:
GetWindowsDirectoryA,
GetCurrentDirectoryA and,
GetLocalTime.
All this information will be
displayed by this program, and the memory and time will be updated
every second, by calling an onTimer[] event handler.
This timer
will trigger an onPaint[] event handler, which will then update the
displayed information.
A pointer to kernel32.dll is created in
the onOpen[] event handler, which also creates our timer, sets our
timer value to 1 second, and fetches our directory information.
--
sysinfo.exw
-- dynamically displays some system information.
-- wolf/Jan.23/99
include win32lib.ew
without warning
global constant
MemWin = create( Window, "", 0, 0, 0, 400, 140, 0 ),
MyTimer = 1,
-- links to our API functions
zGlobalMemoryStatus = registerw32Procedure( kernel32, "GlobalMemoryStatus", {C_POINTER} ),
zGetWindowsDirectory = registerw32Procedure( kernel32, "GetWindowsDirectoryA", {C_POINTER, C_INT} ),
zGetCurrentDirectory = registerw32Function( kernel32, "GetCurrentDirectoryA", {C_INT, C_POINTER}, C_INT ),
zGetCurrentTime = registerw32Procedure(kernel32, "GetLocalTime", {C_POINTER} )
sequence meminfo, windirstring, currentdirstring
atom buffer
procedure GetMemory()
buffer = allocate(32)
poke4(buffer,32)
w32Proc(zGlobalMemoryStatus,{buffer})
meminfo = peek4u({buffer,8})
free(buffer)
end procedure
-- GetWindowsDirectoryA requires a pointer to the allocated memory,
-- and the value of its length.
-- ( 100 here 'should' be long enough, we hope! )
-- It puts a zero terminated string into the allocated buffer.
function GetWindowsDir()
sequence WinDir
integer i
buffer = allocate(100)
w32Proc(zGetWindowsDirectory, {buffer, 100})
WinDir = ""
i = 0
while peek(buffer+i) != 0 do
WinDir = WinDir & peek(buffer+i)
i = i+1
end while
free(buffer)
return WinDir
end function
-- GetCurrentDirectoryA requires a length value,
-- and a pointer to the allocated memory.
-- It also puts a zero terminated string into the allocated buffer.
function GetCurrentDir()
sequence CurrentDir
atom i, ok
buffer = allocate(4) -- first get the length using this dummy length.
i=w32Func(zGetCurrentDirectory, {4, buffer})
if i=0 then
ok = message_box( "Couldn't link to C function GetCurrentDirectoryA",
"Win32 Error", MB_ICONHAND+MB_TASKMODAL )
free(buffer)
abort(1)
end if
free(buffer)
buffer = allocate(i) -- do it again, with the correct length this time!
i=w32Func(zGetCurrentDirectory, {i, buffer})
CurrentDir = ""
i = 0
while peek(buffer+i) != 0 do
CurrentDir = CurrentDir & peek(buffer+i)
i = i+1
end while
free(buffer)
return CurrentDir
end function
-- and here's the 'time' structure, used by the next function.
-- WORD wYear;
-- WORD wMonth;
-- WORD wDayOfWeek;
-- WORD wDay;
-- WORD wHour;
-- WORD wMinute;
-- WORD wSecond;
-- WORD wMilliseconds;
-- where a WORD is 2 bytes.
function Getcurrenttime()
sequence currenttime
buffer = allocate(16)
w32Proc(zGetCurrentTime, {buffer})
currenttime = ""
for i = 0 to 15 do
currenttime = currenttime & peek(buffer+i)
end for
free(buffer)
return currenttime
end function
procedure onPaint_MemWin(atom self, atom event, sequence params )
sequence s, t, string1
GetMemory()
setPenPos(MemWin,2,2)
string1= "bytes of memory = " & sprintf("%d",meminfo[3])
wPuts(MemWin,string1)
setPenPos(MemWin,2,20)
string1= "percent of memory in use = " & sprintf("%d",meminfo[2]) & "%"
wPuts(MemWin,string1 & " - including 'virtual cache'.")
setPenPos(MemWin,2,38)
string1= "free memory bytes = " & sprintf("%d",meminfo[4])
wPuts(MemWin,string1)
setPenPos(MemWin,2,56)
wPuts(MemWin,"Windows directory = " & windirstring)
setPenPos(MemWin,2,74)
wPuts(MemWin,"this program's directory")
setPenPos(MemWin,2,92)
wPuts(MemWin,"= " & currentdirstring)
s=Getcurrenttime()
t=sprintf("%02d",s[9..10]) & ":" & sprintf("%02d",s[11.12])
& ":" & sprintf("%02d",s[13..14])
setText(MemWin,t & " - - System Info - -"
end procedure
procedure onTimer_MemWin( atom self, atom event, sequence params )
repaintWindow( MemWin )
end procedure
procedure onOpen_MemWin(atom self, atom event, sequence params )
atom kernel32
kernel32 = open_dll("kernel32.dll")
if kernel32 = 0 then
puts(1,"Couldn't open kernel32.dll!\n")
end if
setTimer( MemWin, MyTimer, 1000 )
windirstring=GetWindowsDir()
currentdirstring=GetCurrentDir()
end procedure
setHandler( MemWin, w32HOpen, routine_id( "onOpen_MemWin" ) )
setHandler( MemWin, w32HTimer, routine_id( "onTimer_MemWin" ) )
setHandler( MemWin, w32HPaint, routine_id( "onPaint_MemWin" ) )
WinMain(MemWin,Normal)
----
As most of you probably know, Euphoria has it's own functions for getting time and getting the current directory, but I decided to illustrate the 'Windows' way here, just as a simple example of accessing DLL's.
If you study the code and the Win32 Programmers Reference, you will also probably notice I have taken a short-cut in the GetWindowsDir() function, by calling it as a procedure, and ignoring the returned value of the call to the GetWindowsDirectoryA function. ...seems to work though.
The illustrated call to GetCurrentDirectoryA is a much more 'proper' call to a function, and includes some error checking as well, but it's still not perfect.
Note also, that this function is actually called twice. It is used the first time just to get a length value in ( buffer ) for the length of the directory 'string', since we don't know ahead of time, what it will be. In our code for GetWindowsDir(), we just took a guess as to the maximum length of the string, ( 100 ), and hoped it would be long enough.
I have also included a
simple variation of the above program:
meminfo.exw,
which displays just the memory info, with the percentage displayed in
the window title, so if you minimize the program, it will display
this in the taskbar. ...enjoy!
While I'm here, I should point out that meminfo.exw, and 3 other examples in these 'tuts', refer to onDestroy[], which doesn't even work in win32lib's versions 0.55.1, or 0.55.5. No major concern, and fixed in subsequent versions.
..end of lesson.