System Services

   

System service functions allow an application to manage and monitor resources, provide access to files, folders, input and output devices, as well as enable an application to log events and handle errors and exceptions. Furthermore, system services functions provide features that can be used to create other types of applications, such as console applications and driver services.

The Windows kernel library ( kernel32.dll ) provides a majority of the low-level system service support for the operating environment. This includes file access, inter-process communication (IPC), memory and resource management, and multitasking and multithreading support. All Windows applications use the Windows kernel to operate . For instance, when an application needs memory (both at startup and during execution), it requires the Windows kernel to allocate the necessary memory.

These key aspects of the system services are described in Table 14.4.

Table 14.4. Key System Services

Feature

Description

Atoms

Support for sharing strings with applications through 16-bit integer identifiers. Functions include AddAtom() and FindAtom() .

Clipboard

IPC support for transferring data between applications or within an application. Common functions include GetClipboardData() and SetClipboardData() . Communication support for communication resources, such as serial ports, parallel ports, modems, and device driver I/O within an application. Functions include DeviceIoControl() , SetupComm() , and SetCommState() .

Console Support

Support of input/output management for character-mode (non-GUI) applications. Involves the use of an input buffer for capturing keyboard and mouse events, and one or more screen buffers for character and color data output. Functions include AllocConsole() and FreeConsole() .

Debugging

Provides event-driven support for application debugging. Functions such as DebugActiveProcess() and WaitForDebugEvent() enable an application to debug events, cause breakpoint exceptions, and transfer execution control to the debugger.

Dynamic Data Exchange (DDE)

IPC support for transferring data between applications. DDE functions such as DdeNameService() and DdeConnect() are provided through the user library ( user32.dll ), but requires access to the DDE Management Library ( ddeml.dll ).

Dynamic Link Library (DLL)

Support for creating and managing libraries that can be loaded by an application at runtime. Functions include LoadLibrary() and FreeLibrary() .

Error Message

Support for handling messages such as MessageBeep() and FlashWindow() . Error Message functions are actually supported by the user library ( user32.dll ).

Event Logging

Support for recording application events into a log such as RegisterEventSource() .

File Mapping

IPC support for mapping a file's contents to a virtual address location, such as CreateFileMapping() .

Files

Support for file input and output of storage media such as CopyFile() and CreateDirectory() .

Handles and Objects

Support for creating and managing handles and objects that provide an abstract and secure access to Windows system resources, such as SetHandleInformation() .

Help Support

Support routines used in conjunction with the Windows Help application, such as WinHelp() . Help support is actually provided by the user library ( user32.dll ), but Microsoft considers help support to be a facet of system services.

Large Integer Operations

Support for 64-bit integer operations. Functions include Int32x32To64() , UInt32x32To64() , and MulDiv() .

Mailslots

Support for creating and managing one-way IPC (mailslots) over a network. Functions include CreateMailslot() , GetMailslotInfo() , and SetMailslotInfo() .

Memory Management

Support for allocating and using memory. Functions include GlobalAlloc() , FillMemory() , and CopyMemory() .

Pipes

Support for creating, managing, and using pipes. Pipes are IPC communication conduits that enable one process to communicate with another process. Functions include CreatePipe() and GetNamedPipeInfo() .

Portable Execution (PE) File Manipulation

Support for manipulating or accessing a portable executable (PE) binary image, which is created by a compatible Win32 linker. The IMAGEHLP DLL provides PE functions that support image access, modification, integrity checking, plus debugging services. Functions include BindImage() , StackWalk() , and SymEnumerateModules() .

Power Management

Provides functions and messages that reveal the system power status and notify of power management events. Functions include GetSystemPowerStatus() and SetSystemPowerStatus() .

Process and Thread Management

Support for multitasking, scheduling, creating, and managing multiple threads and child processes within an application. Functions include CreateProcess() and CreateThread() .

Registry

Support for storing, accessing, and managing the Windows system-defined database with application and system component configuration data. Functions include RegOpenKey() , RegEnumKey() , and RegSaveKey() .

Security

NT support for granting or denying application and user access to an object. Many of the security routines are provided by the Advanced API library ( advapi32.dll ). Functions include SetFileSecurity() and GetFileSecurity() .

Services

Support for automated services in which an application (or driver) can operate without user intervention (or user knowledge). Support for these types of applications is controlled by the Service Control Manager (SCM). The Advanced API library ( advapi32.dll ) provides many of the service routines. Functions include CreateService() and StartService() .

String Manipulation

Support for copying, comparing, sorting, formatting, and converting character strings and determining character types. Provides Unicode support. Functions include lstrcat() , CharLower() , and IsCharAlpha() .

Structured Exception Handling

Provides compiler support for exception handling and termination. Functions include RaiseException() and GetExceptionCode() .

Synchronization

Provides mechanisms that threads can use to synchronize access to a resource. Functions include CreateMutex() and WaitForSingleObject() .

System Information

Support for determining and retrieving system information such as computer name , username, environment variables settings, processor type, and system-color information. Functions include GetSystemInfo() and GetSysColor() .

System Messages

Support for notifying applications and drivers of device change events. System Message support is provided by the user library ( user32.dll ). Functions include RegisterWindowMessage() , SendMessage() , and PostMessage() , which are also used to provide Windows Management support.

System Shutdown

Support for logging off the current user or shutting down the system. System Shutdown support is provided by both the user32.dll and advapi32.dll . Functions include ExitWindows() and InititateSystemShutdown() .

Tape Backup

Support for enabling backup applications to perform tape read/write and initialization and retrieving tape and drive information. Functions include CreateTapePartition() and GetTapeParameters() .

Time

Support for retrieving and setting the date and the time for the system, files, and the local time zone. Functions include GetFileTime() and SetSystemTime() .

Window Stations and Desktops

Service support for secured objects (called window stations and desktops) in making USER32 and GDI32 function calls, regardless of the user logon status. Intended for developers of services, not application developers. Functions include CreateWindowStation() and CloseDesktop() , which is provided by the user library ( user32.dll ).

As you can see, there are vast amounts of system services provided by the Win32 API. In fact, there are more than 750 system service routines alone in the kernel library ( kernel32.dll ), and more system service support provided by the user library ( usr32.dll ) and ancillary libraries such as the imagehlp.dll and advapi32.dll . To view the full list of the available functions provided by these libraries, use Borland's impdef command-line tool or the DLL LIB Util utility, described in the Tip earlier.

Let's now look at some example code in C++Builder that uses a few of the System Services routines mentioned in Table 14.4.

System Services Example

In the source code that's provided on the CD-ROM for this chapter is a project called WinSysUtil . This project contains sample code that utilizes several useful System Services API calls for attaining system, memory, disk, and file information. The WinSysUtil application is illustrated in Figure 14.5

Figure 14.5. Windows System Services Utility screen shot.

graphics/14fig05.jpg

In this sample, we'll examine four different aspects of the program that demonstrate the application of System Services for retrieving system, memory, disk, and file information.

System Information

System Information includes such things as determining login names, computer names , and the Windows version. Listing 14.4 shows some of the source code used to attain and display system information.

Listing 14.4 System Service Utility ” System Information
 void __fastcall TFormSystemService::ButtonSystemInfoClick(TObject *Sender)  {      // get user      char name[MAX_PATH];      DWORD size = MAX_PATH;      GetUserName(name, &size);   // Win32 API call      LabelUser->Caption = AnsiString(name);      // get computer name      char computername[MAX_COMPUTERNAME_LENGTH];      size = MAX_COMPUTERNAME_LENGTH;      GetComputerName(computername, &size);   // Win32 API call      EditComputer->Text = ComputerName();      // let's get the windows version      char os[MAX_PATH];      char version[MAX_PATH];      char patch[MAX_PATH];      bool NT = WindowsVersion(os,version,patch);  // Win32 API "wrapper"      LabelOS->Caption = AnsiString(os);      LabelVersion->Caption = AnsiString(version);      LabelOther->Caption = AnsiString(patch);      // let's get the processor info      char processor[MAX_PATH];      LabelNumProcessors->Caption =                  ProcessorInfo(NT,processor); // Win32 API "wrapper"      LabelProcessor->Caption = AnsiString(processor);      LabelScreenSize->Caption = ScreenSize();      char dir[MAX_PATH];      dir[0] = ' 
 void __fastcall TFormSystemService::ButtonSystemInfoClick(TObject *Sender) { // get user char name[MAX_PATH]; DWORD size = MAX_PATH; GetUserName(name, &size); // Win32 API call LabelUser->Caption = AnsiString(name); // get computer name char computername[MAX_COMPUTERNAME_LENGTH]; size = MAX_COMPUTERNAME_LENGTH; GetComputerName(computername, &size); // Win32 API call EditComputer->Text = ComputerName (); // let's get the windows version char os[MAX_PATH]; char version[MAX_PATH]; char patch[MAX_PATH]; bool NT = WindowsVersion(os,version,patch); // Win32 API "wrapper" LabelOS->Caption = AnsiString(os); LabelVersion->Caption = AnsiString(version); LabelOther->Caption = AnsiString(patch); // let's get the processor info char processor[MAX_PATH]; LabelNumProcessors->Caption = ProcessorInfo(NT,processor); // Win32 API "wrapper" LabelProcessor->Caption = AnsiString(processor); LabelScreenSize->Caption = ScreenSize(); char dir[MAX_PATH]; dir[0] = '\0'; GetWindowsDirectory(dir,MAX_PATH); LabelWinDir->Caption = AnsiString(dir); dir[0] = '\0'; GetSystemDirectory(dir,MAX_PATH); LabelSysDir->Caption = AnsiString(dir); dir[0] = '\0'; GetTempPath(MAX_PATH, dir); LabelTempDir->Caption = AnsiString(dir); } //--------------------------------------------------------------------------- bool __fastcall TFormSystemService::WindowsVersion(char * os, char * version, char * other) { bool NT = false; OSVERSIONINFO version_info; version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); // initilize size GetVersionEx(&version_info); // now let's get version info - Win32 API call if(version_info.dwMajorVersion < 4) // must be win nt 3.x { sprintf(os,"Windows NT "); sprintf(version,"3.x"); } else { sprintf(version,"%d.%d.%04d",version_info.dwMajorVersion, version_info.dwMinorVersion, version_info.dwBuildNumber); } switch (version_info.dwPlatformId) { case VER_PLATFORM_WIN32s: sprintf(os,"%s","Microsoft Win32s"); break; case VER_PLATFORM_WIN32_WINDOWS: sprintf(os,"%s","Microsoft Windows 95/98"); break; case VER_PLATFORM_WIN32_NT: NT = true; switch (version_info.dwMajorVersion) { case 4: sprintf(os,"%s","Microsoft Windows NT"); break; case 5: sprintf(os,"%s","Microsoft Windows 2000"); break; case 6: sprintf(os,"%s","Microsoft Windows XP"); break; default : sprintf(os,"%s","Microsoft Windows ??"); } break; default : // unknown sprintf(os,"%s","Microsoft Windows ??"); } sprintf(other,"%s",version_info.szCSDVersion); return NT; } //--------------------------------------------------------------------------- int __fastcall TFormSystemService::ProcessorInfo(bool NT, char* processor) { SYSTEM_INFO sys_info; AnsiString Processor; AnsiString Level = ""; GetSystemInfo(&sys_info); // determine processor type - Win32 API call int value; if (NT) { switch (sys_info.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL : Processor = "Intel"; switch (sys_info.wProcessorLevel) { case 3 : Level = "80386"; break; case 4 : Level = "80486"; break; case 5 : Level = "Pentium"; break; case 6 : value = HIBYTE(sys_info.wProcessorRevision); switch (value) { case 1 : Level = "Pentium PRO"; break; case 3,5 : Level = "Pentium 2"; break; case 6 : Level = "Celeron"; break; case 7,8,10,11 : Level = "Pentium 3"; break; } break; case 15 : Level = "Pentium 4"; break; default : Level = "unknown"; } break; case PROCESSOR_ARCHITECTURE_ALPHA : Processor = "ALPHA"; switch (sys_info.wProcessorLevel) { case 21064 : Level = "21064"; break; case 21066 : Level = "21066"; break; case 21164 : Level = "21164"; break; default : Level = "unknown"; } break; case PROCESSOR_ARCHITECTURE_MIPS : Processor = "MIPS"; switch (sys_info.wProcessorLevel) { case 0004 : Level = "R4000"; break; default : Level = "unknown"; } break; case PROCESSOR_ARCHITECTURE_PPC : Processor = "PPC"; switch (sys_info.wProcessorLevel) { case 1 : Level = "601"; break; case 3 : Level = "603"; break; case 4 : Level = "604"; break; case 6 : Level = "603+"; break; case 9 : Level = "604+"; break; case 20 : Level = "620"; break; default : Level = "unknown"; } break; default : Processor = "unknown"; } } else // Win 9x { switch (sys_info.dwProcessorType) { case PROCESSOR_INTEL_386 : Processor = "Intel"; Level = "80386"; break; case PROCESSOR_INTEL_486 : Processor = "Intel"; Level = "80486"; break; case PROCESSOR_INTEL_PENTIUM : Processor = "Intel"; Level = "Pentium"; break; default: Processor = "unknown"; } } sprintf(processor,"%s %s",Processor.c_str(),Level.c_str()); return sys_info.dwNumberOfProcessors; } //--------------------------------------------------------------------------- AnsiString TFormSystemService::ScreenSize() { AnsiString value; RECT screen_coords; SystemParametersInfo(SPI_GETWORKAREA,0, &screen_coords, 0); //Win32 API call int width = screen_coords.right - screen_coords.left; int height = screen_coords.bottom - screen_coords.top; /* // here's another way, but width and height is obsurced by the tray int height = GetSystemMetrics(SM_CYFULLSCREEN); int width = GetSystemMetrics(SM_CXFULLSCREEN); */ value = AnsiString(width) + " x " + AnsiString(height) + " pixels"; return value; } //--------------------------------------------------------------------------- void __fastcall TFormSystemService::ButtonChangeComputerClick(TObject *Sender) { SetComputerName(EditComputer->Text.c_str()); if (MessageBox(Handle,"You must reboot system for change to take affect.", "Reboot System?",MB_YESNO) == IDYES) { bool success = ExitWindowsEx(EWX_REBOOT, 0); if (!success) MessageBox(Handle, "Unable to shutdown system due to a system restriction.", "System Restriction",MB_OK); else Close(); } } 
'; GetWindowsDirectory(dir,MAX_PATH); LabelWinDir->Caption = AnsiString(dir); dir[0] = '
 void __fastcall TFormSystemService::ButtonSystemInfoClick(TObject *Sender) { // get user char name[MAX_PATH]; DWORD size = MAX_PATH; GetUserName(name, &size); // Win32 API call LabelUser->Caption = AnsiString(name); // get computer name char computername[MAX_COMPUTERNAME_LENGTH]; size = MAX_COMPUTERNAME_LENGTH; GetComputerName(computername, &size); // Win32 API call EditComputer->Text = ComputerName (); // let's get the windows version char os[MAX_PATH]; char version[MAX_PATH]; char patch[MAX_PATH]; bool NT = WindowsVersion(os,version,patch); // Win32 API "wrapper" LabelOS->Caption = AnsiString(os); LabelVersion->Caption = AnsiString(version); LabelOther->Caption = AnsiString(patch); // let's get the processor info char processor[MAX_PATH]; LabelNumProcessors->Caption = ProcessorInfo(NT,processor); // Win32 API "wrapper" LabelProcessor->Caption = AnsiString(processor); LabelScreenSize->Caption = ScreenSize(); char dir[MAX_PATH]; dir[0] = '\0'; GetWindowsDirectory(dir,MAX_PATH); LabelWinDir->Caption = AnsiString(dir); dir[0] = '\0'; GetSystemDirectory(dir,MAX_PATH); LabelSysDir->Caption = AnsiString(dir); dir[0] = '\0'; GetTempPath(MAX_PATH, dir); LabelTempDir->Caption = AnsiString(dir); } //--------------------------------------------------------------------------- bool __fastcall TFormSystemService::WindowsVersion(char * os, char * version, char * other) { bool NT = false; OSVERSIONINFO version_info; version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); // initilize size GetVersionEx(&version_info); // now let's get version info - Win32 API call if(version_info.dwMajorVersion < 4) // must be win nt 3.x { sprintf(os,"Windows NT "); sprintf(version,"3.x"); } else { sprintf(version,"%d.%d.%04d",version_info.dwMajorVersion, version_info.dwMinorVersion, version_info.dwBuildNumber); } switch (version_info.dwPlatformId) { case VER_PLATFORM_WIN32s: sprintf(os,"%s","Microsoft Win32s"); break; case VER_PLATFORM_WIN32_WINDOWS: sprintf(os,"%s","Microsoft Windows 95/98"); break; case VER_PLATFORM_WIN32_NT: NT = true; switch (version_info.dwMajorVersion) { case 4: sprintf(os,"%s","Microsoft Windows NT"); break; case 5: sprintf(os,"%s","Microsoft Windows 2000"); break; case 6: sprintf(os,"%s","Microsoft Windows XP"); break; default : sprintf(os,"%s","Microsoft Windows ??"); } break; default : // unknown sprintf(os,"%s","Microsoft Windows ??"); } sprintf(other,"%s",version_info.szCSDVersion); return NT; } //--------------------------------------------------------------------------- int __fastcall TFormSystemService::ProcessorInfo(bool NT, char* processor) { SYSTEM_INFO sys_info; AnsiString Processor; AnsiString Level = ""; GetSystemInfo(&sys_info); // determine processor type - Win32 API call int value; if (NT) { switch (sys_info.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL : Processor = "Intel"; switch (sys_info.wProcessorLevel) { case 3 : Level = "80386"; break; case 4 : Level = "80486"; break; case 5 : Level = "Pentium"; break; case 6 : value = HIBYTE(sys_info.wProcessorRevision); switch (value) { case 1 : Level = "Pentium PRO"; break; case 3,5 : Level = "Pentium 2"; break; case 6 : Level = "Celeron"; break; case 7,8,10,11 : Level = "Pentium 3"; break; } break; case 15 : Level = "Pentium 4"; break; default : Level = "unknown"; } break; case PROCESSOR_ARCHITECTURE_ALPHA : Processor = "ALPHA"; switch (sys_info.wProcessorLevel) { case 21064 : Level = "21064"; break; case 21066 : Level = "21066"; break; case 21164 : Level = "21164"; break; default : Level = "unknown"; } break; case PROCESSOR_ARCHITECTURE_MIPS : Processor = "MIPS"; switch (sys_info.wProcessorLevel) { case 0004 : Level = "R4000"; break; default : Level = "unknown"; } break; case PROCESSOR_ARCHITECTURE_PPC : Processor = "PPC"; switch (sys_info.wProcessorLevel) { case 1 : Level = "601"; break; case 3 : Level = "603"; break; case 4 : Level = "604"; break; case 6 : Level = "603+"; break; case 9 : Level = "604+"; break; case 20 : Level = "620"; break; default : Level = "unknown"; } break; default : Processor = "unknown"; } } else // Win 9x { switch (sys_info.dwProcessorType) { case PROCESSOR_INTEL_386 : Processor = "Intel"; Level = "80386"; break; case PROCESSOR_INTEL_486 : Processor = "Intel"; Level = "80486"; break; case PROCESSOR_INTEL_PENTIUM : Processor = "Intel"; Level = "Pentium"; break; default: Processor = "unknown"; } } sprintf(processor,"%s %s",Processor.c_str(),Level.c_str()); return sys_info.dwNumberOfProcessors; } //--------------------------------------------------------------------------- AnsiString TFormSystemService::ScreenSize() { AnsiString value; RECT screen_coords; SystemParametersInfo(SPI_GETWORKAREA,0, &screen_coords, 0); //Win32 API call int width = screen_coords.right - screen_coords.left; int height = screen_coords.bottom - screen_coords.top; /* // here's another way, but width and height is obsurced by the tray int height = GetSystemMetrics(SM_CYFULLSCREEN); int width = GetSystemMetrics(SM_CXFULLSCREEN); */ value = AnsiString(width) + " x " + AnsiString(height) + " pixels"; return value; } //--------------------------------------------------------------------------- void __fastcall TFormSystemService::ButtonChangeComputerClick(TObject *Sender) { SetComputerName(EditComputer->Text.c_str()); if (MessageBox(Handle,"You must reboot system for change to take affect.", "Reboot System?",MB_YESNO) == IDYES) { bool success = ExitWindowsEx(EWX_REBOOT, 0); if (!success) MessageBox(Handle, "Unable to shutdown system due to a system restriction.", "System Restriction",MB_OK); else Close(); } } 
'; GetSystemDirectory(dir,MAX_PATH); LabelSysDir->Caption = AnsiString(dir); dir[0] = '
 void __fastcall TFormSystemService::ButtonSystemInfoClick(TObject *Sender) { // get user char name[MAX_PATH]; DWORD size = MAX_PATH; GetUserName(name, &size); // Win32 API call LabelUser->Caption = AnsiString(name); // get computer name char computername[MAX_COMPUTERNAME_LENGTH]; size = MAX_COMPUTERNAME_LENGTH; GetComputerName(computername, &size); // Win32 API call EditComputer->Text = ComputerName (); // let's get the windows version char os[MAX_PATH]; char version[MAX_PATH]; char patch[MAX_PATH]; bool NT = WindowsVersion(os,version,patch); // Win32 API "wrapper" LabelOS->Caption = AnsiString(os); LabelVersion->Caption = AnsiString(version); LabelOther->Caption = AnsiString(patch); // let's get the processor info char processor[MAX_PATH]; LabelNumProcessors->Caption = ProcessorInfo(NT,processor); // Win32 API "wrapper" LabelProcessor->Caption = AnsiString(processor); LabelScreenSize->Caption = ScreenSize(); char dir[MAX_PATH]; dir[0] = '\0'; GetWindowsDirectory(dir,MAX_PATH); LabelWinDir->Caption = AnsiString(dir); dir[0] = '\0'; GetSystemDirectory(dir,MAX_PATH); LabelSysDir->Caption = AnsiString(dir); dir[0] = '\0'; GetTempPath(MAX_PATH, dir); LabelTempDir->Caption = AnsiString(dir); } //--------------------------------------------------------------------------- bool __fastcall TFormSystemService::WindowsVersion(char * os, char * version, char * other) { bool NT = false; OSVERSIONINFO version_info; version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); // initilize size GetVersionEx(&version_info); // now let's get version info - Win32 API call if(version_info.dwMajorVersion < 4) // must be win nt 3.x { sprintf(os,"Windows NT "); sprintf(version,"3.x"); } else { sprintf(version,"%d.%d.%04d",version_info.dwMajorVersion, version_info.dwMinorVersion, version_info.dwBuildNumber); } switch (version_info.dwPlatformId) { case VER_PLATFORM_WIN32s: sprintf(os,"%s","Microsoft Win32s"); break; case VER_PLATFORM_WIN32_WINDOWS: sprintf(os,"%s","Microsoft Windows 95/98"); break; case VER_PLATFORM_WIN32_NT: NT = true; switch (version_info.dwMajorVersion) { case 4: sprintf(os,"%s","Microsoft Windows NT"); break; case 5: sprintf(os,"%s","Microsoft Windows 2000"); break; case 6: sprintf(os,"%s","Microsoft Windows XP"); break; default : sprintf(os,"%s","Microsoft Windows ??"); } break; default : // unknown sprintf(os,"%s","Microsoft Windows ??"); } sprintf(other,"%s",version_info.szCSDVersion); return NT; } //--------------------------------------------------------------------------- int __fastcall TFormSystemService::ProcessorInfo(bool NT, char* processor) { SYSTEM_INFO sys_info; AnsiString Processor; AnsiString Level = ""; GetSystemInfo(&sys_info); // determine processor type - Win32 API call int value; if (NT) { switch (sys_info.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL : Processor = "Intel"; switch (sys_info.wProcessorLevel) { case 3 : Level = "80386"; break; case 4 : Level = "80486"; break; case 5 : Level = "Pentium"; break; case 6 : value = HIBYTE(sys_info.wProcessorRevision); switch (value) { case 1 : Level = "Pentium PRO"; break; case 3,5 : Level = "Pentium 2"; break; case 6 : Level = "Celeron"; break; case 7,8,10,11 : Level = "Pentium 3"; break; } break; case 15 : Level = "Pentium 4"; break; default : Level = "unknown"; } break; case PROCESSOR_ARCHITECTURE_ALPHA : Processor = "ALPHA"; switch (sys_info.wProcessorLevel) { case 21064 : Level = "21064"; break; case 21066 : Level = "21066"; break; case 21164 : Level = "21164"; break; default : Level = "unknown"; } break; case PROCESSOR_ARCHITECTURE_MIPS : Processor = "MIPS"; switch (sys_info.wProcessorLevel) { case 0004 : Level = "R4000"; break; default : Level = "unknown"; } break; case PROCESSOR_ARCHITECTURE_PPC : Processor = "PPC"; switch (sys_info.wProcessorLevel) { case 1 : Level = "601"; break; case 3 : Level = "603"; break; case 4 : Level = "604"; break; case 6 : Level = "603+"; break; case 9 : Level = "604+"; break; case 20 : Level = "620"; break; default : Level = "unknown"; } break; default : Processor = "unknown"; } } else // Win 9x { switch (sys_info.dwProcessorType) { case PROCESSOR_INTEL_386 : Processor = "Intel"; Level = "80386"; break; case PROCESSOR_INTEL_486 : Processor = "Intel"; Level = "80486"; break; case PROCESSOR_INTEL_PENTIUM : Processor = "Intel"; Level = "Pentium"; break; default: Processor = "unknown"; } } sprintf(processor,"%s %s",Processor.c_str(),Level.c_str()); return sys_info.dwNumberOfProcessors; } //--------------------------------------------------------------------------- AnsiString TFormSystemService::ScreenSize() { AnsiString value; RECT screen_coords; SystemParametersInfo(SPI_GETWORKAREA,0, &screen_coords, 0); //Win32 API call int width = screen_coords.right - screen_coords.left; int height = screen_coords.bottom - screen_coords.top; /* // here's another way, but width and height is obsurced by the tray int height = GetSystemMetrics(SM_CYFULLSCREEN); int width = GetSystemMetrics(SM_CXFULLSCREEN); */ value = AnsiString(width) + " x " + AnsiString(height) + " pixels"; return value; } //--------------------------------------------------------------------------- void __fastcall TFormSystemService::ButtonChangeComputerClick(TObject *Sender) { SetComputerName(EditComputer->Text.c_str()); if (MessageBox(Handle,"You must reboot system for change to take affect.", "Reboot System?",MB_YESNO) == IDYES) { bool success = ExitWindowsEx(EWX_REBOOT, 0); if (!success) MessageBox(Handle, "Unable to shutdown system due to a system restriction.", "System Restriction",MB_OK); else Close(); } } 
'; GetTempPath(MAX_PATH, dir); LabelTempDir->Caption = AnsiString(dir); } //--------------------------------------------------------------------------- bool __fastcall TFormSystemService::WindowsVersion(char * os, char * version, char * other) { bool NT = false; OSVERSIONINFO version_info; version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); // initilize size GetVersionEx(&version_info); // now let's get version info - Win32 API call if(version_info.dwMajorVersion < 4) // must be win nt 3.x { sprintf(os,"Windows NT "); sprintf(version,"3.x"); } else { sprintf(version,"%d.%d.%04d",version_info.dwMajorVersion, version_info.dwMinorVersion, version_info.dwBuildNumber); } switch (version_info.dwPlatformId) { case VER_PLATFORM_WIN32s: sprintf(os,"%s","Microsoft Win32s"); break; case VER_PLATFORM_WIN32_WINDOWS: sprintf(os,"%s","Microsoft Windows 95/98"); break; case VER_PLATFORM_WIN32_NT: NT = true; switch (version_info.dwMajorVersion) { case 4: sprintf(os,"%s","Microsoft Windows NT"); break; case 5: sprintf(os,"%s","Microsoft Windows 2000"); break; case 6: sprintf(os,"%s","Microsoft Windows XP"); break; default : sprintf(os,"%s","Microsoft Windows ??"); } break; default : // unknown sprintf(os,"%s","Microsoft Windows ??"); } sprintf(other,"%s",version_info.szCSDVersion); return NT; } //--------------------------------------------------------------------------- int __fastcall TFormSystemService::ProcessorInfo(bool NT, char* processor) { SYSTEM_INFO sys_info; AnsiString Processor; AnsiString Level = ""; GetSystemInfo(&sys_info); // determine processor type - Win32 API call int value; if (NT) { switch (sys_info.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL : Processor = "Intel"; switch (sys_info.wProcessorLevel) { case 3 : Level = "80386"; break; case 4 : Level = "80486"; break; case 5 : Level = "Pentium"; break; case 6 : value = HIBYTE(sys_info.wProcessorRevision); switch (value) { case 1 : Level = "Pentium PRO"; break; case 3,5 : Level = "Pentium 2"; break; case 6 : Level = "Celeron"; break; case 7,8,10,11 : Level = "Pentium 3"; break; } break; case 15 : Level = "Pentium 4"; break; default : Level = "unknown"; } break; case PROCESSOR_ARCHITECTURE_ALPHA : Processor = "ALPHA"; switch (sys_info.wProcessorLevel) { case 21064 : Level = "21064"; break; case 21066 : Level = "21066"; break; case 21164 : Level = "21164"; break; default : Level = "unknown"; } break; case PROCESSOR_ARCHITECTURE_MIPS : Processor = "MIPS"; switch (sys_info.wProcessorLevel) { case 0004 : Level = "R4000"; break; default : Level = "unknown"; } break; case PROCESSOR_ARCHITECTURE_PPC : Processor = "PPC"; switch (sys_info.wProcessorLevel) { case 1 : Level = "601"; break; case 3 : Level = "603"; break; case 4 : Level = "604"; break; case 6 : Level = "603+"; break; case 9 : Level = "604+"; break; case 20 : Level = "620"; break; default : Level = "unknown"; } break; default : Processor = "unknown"; } } else // Win 9x { switch (sys_info.dwProcessorType) { case PROCESSOR_INTEL_386 : Processor = "Intel"; Level = "80386"; break; case PROCESSOR_INTEL_486 : Processor = "Intel"; Level = "80486"; break; case PROCESSOR_INTEL_PENTIUM : Processor = "Intel"; Level = "Pentium"; break; default: Processor = "unknown"; } } sprintf(processor,"%s %s",Processor.c_str(),Level.c_str()); return sys_info.dwNumberOfProcessors; } //--------------------------------------------------------------------------- AnsiString TFormSystemService::ScreenSize() { AnsiString value; RECT screen_coords; SystemParametersInfo(SPI_GETWORKAREA,0, &screen_coords, 0); //Win32 API call int width = screen_coords.right - screen_coords.left; int height = screen_coords.bottom - screen_coords.top; /* // here's another way, but width and height is obsurced by the tray int height = GetSystemMetrics(SM_CYFULLSCREEN); int width = GetSystemMetrics(SM_CXFULLSCREEN); */ value = AnsiString(width) + " x " + AnsiString(height) + " pixels"; return value; } //--------------------------------------------------------------------------- void __fastcall TFormSystemService::ButtonChangeComputerClick(TObject *Sender) { SetComputerName(EditComputer->Text.c_str()); if (MessageBox(Handle,"You must reboot system for change to take affect.", "Reboot System?",MB_YESNO) == IDYES) { bool success = ExitWindowsEx(EWX_REBOOT, 0); if (!success) MessageBox(Handle, "Unable to shutdown system due to a system restriction.", "System Restriction",MB_OK); else Close(); } }

In this example, the ButtonSystemInfoClick() event handler initiates the system calls in gathering the desired system information when the user clicks Get System Info. The first Win32 API call made is to GetUserName() , which provides the name of the user logged onto the system. A name buffer and the address to the size variable are passed as parameters into the GetUserName() function.

The GetComputerName() API function is used next to retrieve the computer label name identified within the Registry. As you can see in the code listing, GetComputerName() behaves very similar to GetUserName() .

Now, we want to retrieve the Windows version information and display it to the user. The Win32 API call used to gain this information is provided by the GetVersionEx() . However, because of the complexities associated to deciphering the Windows version, we've placed the Windows version processing information inside a custom wrapper function called WindowsVersion() . Our ButtonSystemInfoClick() event handler makes a call to this custom function by passing three character strings: os , version , and patch . In return, we will receive the os label, such as Microsoft Windows 2000; the version , such as 5.00.2195; and patch information, such as Service Pack 2. Plus, a boolean result value will be returned indicating if the OS is of the NT genre or not. This information will be important a little later.

Let's take a closer look at the WindowsVersion() method we've created to handle this version processing. As mentioned earlier, the GetVersionEx() call is used to collect the system information. After this call is made within our custom wrapper function, we need to start examining the fields associated to the version_info variable, which is based on the OSVERSIONINFO structure. The version_info variable contains the following fields:

 DWORD dwOSVersionInfoSize;  DWORD dwMajorVersion;  DWORD dwMinorVersion;  DWORD dwBuildNumber;  DWORD dwPlatformId;  TCHAR szCSDVersion[ 128 ]; 

As shown in the code listing, the WindowsVersion() wrapper function examines the dwMajorVersion and dwPlatformId to determine the Operating System (OS). It then uses dwMajorVersion , dwMinorVersion , and dwBuildNumber to annotate the OS version. And finally, it uses the szCSDVersion character string to identify the latest patch update applied to the OS. If the dwPlatformId value is equal to VER_PLATFORM_WIN32_NT , the function returns a true result to identify that the OS is NT-based.

Let's now step back into the ButtonSystemInfoClick() method and see how we determine the remaining System information. After retrieving the Windows Version information, the next task for our method is to gather and display information regarding the computer's processor. Determining the type of processor is not a trivial task. Over the course of the last decade , an assortment of processors have been introduced, many of which can be supported using current versions of Windows. So, again, we have created a custom method called ProcessorInfo() based on the GetSystemInfo() Win32 API call, which serves as a wrapper for retrieving and dissecting system information and returning a processor type. As one of the inputs, this method needs to know whether the OS is part of the 9x family or if it is NT-based. Fortunately, we determined that piece of information earlier with the WindowsVersion() wrapper. We need it because the application of GetSystemInfo() and the extraction of data from the sys_info variable, which is based on the SYSTEM_INFO structure, varies depending on the OS. Let's take a look at the SYSTEM_INFO structure.

 typedef struct _SYSTEM_INFO { // sinf      union {          DWORD  dwOemId;          struct {              WORD wProcessorArchitecture;              WORD wReserved;          };      };      DWORD  dwPageSize;      LPVOID lpMinimumApplicationAddress;      LPVOID lpMaximumApplicationAddress;      DWORD  dwActiveProcessorMask;      DWORD  dwNumberOfProcessors;      DWORD  dwProcessorType;      DWORD  dwAllocationGranularity;      WORD  wProcessorLevel;      WORD  wProcessorRevision;  } SYSTEM_INFO; 

If the OS is NT-based, the wProcessorArchitecture and wProcessorLevel is used to determine the processor. Otherwise, the dwProcessorType is used for Windows 9x systems. We also use dwNumberOfProcessors to determine the number of processors within the system. If more than one processor exists, we can use the dwActiveProcessorMask to identify the processor we want to examine.

After ButtonSystemInfoClick() receives and displays the processor information, we calculate the available working space (also known as screen size) for the display. Again, we have created a custom function called ScreenSize() that calculates the screen dimensions based on the SystemParametersInfo() Win32 API call. There are other routines, such as GetSystemMetrics() in combination with the SM_CYFULLSCREEN and SM_CXFULLSCREEN flags, that can be used to determine screen space as well. However, the SystemParametersInfo() call with the SPI_GETWORKAREA flag provides screen dimensions not obstructed by the taskbar.

In many applications, it can be useful to know the location of both the Windows and System directories. Sometimes it is also useful to store data or files in a temporary file location such as the Windows Temp directory. The location of these directories, however, can vary on each computer. Fortunately, the Win32 API provides the functionality to obtain this information through the GetWindowsDirectory() , GetSystemDirectory() , and GetTempPath() , respectively.

The last three activities performed by the ButtonSystemInfoClick() event handler retrieves and displays the Windows, Windows System and temporary paths for the OS and uses these API functions. Each of these calls requires two parameters: the size and a string.

CAUTION

You might notice that the order of the parameters among these similar calls is not the same. For some reason the implementer of GetTempPath() unintentionally selected a parameter order that was reverse from the way GetWindowsDirectory() , GetSystemDirectory() , and other routines such as GetUserName() and GetComputerName() were prototyped. Often the assumption is that because these calls all have the first parameter as the address to a string, and the second parameter identifying the string size, the same follows suite for GetTempPath() or any other similar Win32 API function. This proves, once again, that it's good practice to double-check the Help file before going to code.


We have one more feature in this sample code manifested in the ButtonChangeComputerClick() event handler. This handler gets kicked off when the user has decided to change the computer name for the system. The SetComputerName() Win32 API routine provides the capability to make this change happen. For it to take effect, however, the computer needs to be restarted. The ExitWindowsEx() Win32 API provides the capability to do this reboot. Yet, under Windows NT, the user might be restricted in performing automated shutdown and reboots.

ExitWindowsEx() is an easy way to shut down or restart Windows, but you can do a lot more than just shut down Windows. The ExitWindowEx() function has more flags with which to work. The format is as follows:

 BOOL ExitWindowsEx(      UINT uFlags,    // shutdown operation      DWORD dwReserved     // reserved     ); 

uFlags are flags to specify which shutdown type you wish to perform. Table 14.5 shows the values.

Table 14.5. System Shutdown Function Flags

Flags

Value

EWX_FORCE

Forces processes to terminate. When this flag is set, Windows does not send the messages WM_QUERYENDSESSION and WM_ENDSESSION to the applications currently running in the system. This can cause the applications to lose data, so you should use this flag only in an emergency.

EWX_LOGOFF

Shuts down all processes running in the security context of the process that called the ExitWindowsEx() function. Then, it logs the user off.

EWX_POWEROFF

Shuts down the system and turns off the power. The system must support the power-off feature. Windows NT: The calling process must have the SE_SHUTDOWN_NAME privilege. Windows 95: Security privileges are not supported or required.

EWX_REBOOT

Shuts down and restarts the system. Windows NT: The calling process must have the SE_SHUTDOWN_NAME privilege.

EWX_SHUTDOWN

Shuts down the system to a point at which it is safe to turn off the power. All file buffers have been flushed to disk, and all running processes have stopped . Windows NT: The calling process must have the SE_SHUTDOWN_NAME privilege.

The dwReserved parameter is currently not used.

Memory Information

Let's now take a look at a shorter example from this sample that uses the Win32 System Service calls to gather and display the memory information (see Listing 14.5).

Listing 14.5 Windows System Service Utility ”Memory Example
 void __fastcall TFormSystemService::ButtonGetMemInfoClick(TObject *Sender)  {    MEMORYSTATUS memory ;    memory.dwLength = sizeof (memory) ;    GlobalMemoryStatus (&memory) ;    LabelPTotal->Caption  = FormatSize((memory.dwTotalPhys/1024));    LabelPFree->Caption   = FormatSize((memory.dwAvailPhys/1024));    LabelPgTotal->Caption = FormatSize((memory.dwTotalPageFile/1024));    LabelPgFree->Caption  = FormatSize((memory.dwAvailPageFile/1024));    LabelVTotal->Caption  = FormatSize((memory.dwTotalVirtual/1024));    LabelVFree->Caption   = FormatSize((memory.dwAvailVirtual/1024));    double value1 = double(double(memory.dwAvailPhys*100.0)/memory.dwTotalPhys);    double value = 100.0-memory.dwMemoryLoad;    if (value1 > value)       value = long(value1);    LabelFree->Caption  = AnsiString(value) + " % free";;  }  

The ButtonGetMemInfoClick() event handler uses a special Win32 API function called GlobalMemoryStatus() , which enables us to determine memory statistics such as available memory and page size. The MEMORYSTATUS structure used for the memory variable provides the properties that are filled by the GlobalMemoryStatus() call. Let's take a quick look at the MEMORYSTATUS structure.

 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; 

In our example, each of the memory property values calculated by GlobalMemoryStatus() are displayed to the user. Also, the percentage of physical memory available to the system is calculated and displayed. These values and calculations can be extremely useful for your applications in determining performance capabilities and resource restrictions. In fact, the performance between a Windows 9x box and a Windows NT-based box, such as 2000 or XP, can be very revealing when using GlobalMemoryStatus() .

Drive Information

Let's now take a look at some other code from this sample that uses the Win32 System Service calls to provide drive information such as volume name, serial number, and available diskspace (see Listing 14.6).

Listing 14.6 Windows System Service Utility ”Drive Information Example
[View full width]
 void __fastcall TFormSystemService::ButtonGetDriveInfoClick(TObject *Sender)  {    AnsiString temp;    AnsiString Drive = AnsiString(DriveComboBox1->Drive) + ":\"; //EditDrive->Text;    unsigned int drivetype = GetDriveType(Drive.c_str ());    switch (drivetype)    {      case 1 : temp = "No root directory";   return;      case DRIVE_REMOVABLE : temp = "Removable";  break;      case DRIVE_FIXED     : temp = "Fixed";      break;      case DRIVE_REMOTE    : temp = "Remote (network) drive";  break;      case DRIVE_CDROM     : temp = "CD-ROM";     break;      case DRIVE_RAMDISK   : temp = "RAM disk";   break;      default: temp = "Unknown"; return;    }    LabelDriveType->Caption = temp;    temp = "";    DWORD VolumeSerialNumber = 0;    DWORD MaximumComponentLength = 0;    DWORD FileSystemFlags = 0;    char * volumeinfo = new char[255];    volumeinfo[0] = 0;    char* FileSystemNameBuffer = new char[255];    FileSystemNameBuffer[0] = 0;    GetVolumeInformation (Drive.c_str (), volumeinfo,                              255, &VolumeSerialNumber,                              &MaximumComponentLength, &FileSystemFlags, graphics/ccc.gif FileSystemNameBuffer,255);      if (strlen(volumeinfo) != 0)          EditVolumeInfo->Text = volumeinfo ;      else          EditVolumeInfo->Text = "- no label -";      //Translate integer to chars for serial number      char string1[35];      char string2[35];      if (VolumeSerialNumber > 0)      {        unsigned int bottom = (LOWORD(VolumeSerialNumber));        unsigned int top = (HIWORD(VolumeSerialNumber));        sprintf(string1,"%04X",top);        sprintf(string2,"%04X",bottom);        LabelSerialNum->Caption = AnsiString(string1) + "-" + AnsiString(string2);      }      else        LabelSerialNum->Caption = "- unknown -";      if (MaximumComponentLength > 0)        LabelMaxComponentLength->Caption = AnsiString(MaximumComponentLength) + graphics/ccc.gif "characters";      else        LabelMaxComponentLength->Caption = "- unknown -";      if (strlen(FileSystemNameBuffer) != 0)          LabelFileSystemNameBuffer->Caption = FileSystemNameBuffer;      else          LabelFileSystemNameBuffer->Caption = "- unknown -";      LabelFileSystemFlags->Caption = ""; //AnsiString(FileSystemFlags);      if (FileSystemFlags & FS_CASE_IS_PRESERVED)           temp += AnsiString("Filename case is preserved.\n");      if (FileSystemFlags & FS_CASE_SENSITIVE)           temp += AnsiString("Lookup is case-sensitive.\n");      if (FileSystemFlags & FS_UNICODE_STORED_ON_DISK)           temp += AnsiString("Supports Unicode in filenames.\n");      if (FileSystemFlags & FS_PERSISTENT_ACLS)           temp += AnsiString("Preserves and enforces ACLs.\n");      if (FileSystemFlags & FS_FILE_COMPRESSION)           temp += AnsiString("Supports file-based compression.\n");      if (FileSystemFlags & FS_VOL_IS_COMPRESSED)           temp += AnsiString("Volume is compressed. (i.e., DoubleSpace).\n");      LabelFileSystemFlags->Caption = temp;      DWORD spc = 0;    //Sectors per cluster      DWORD bps = 0;    //Bytes per cluster      DWORD cluster = 0;   //clusters      DWORD freeclust = 0;   //freeclusters      GetDiskFreeSpace (Drive.c_str (),&spc,&bps,&freeclust,&cluster) ;      unsigned long v1 = (unsigned long)cluster;      unsigned long v2 = (unsigned long) spc;      unsigned long v3 = (unsigned long) bps;      unsigned long volsize = (v1 * v2)/1024 * v3;      LabelVolumeSize->Caption = AnsiString(FormatSize(volsize));      unsigned long free_bytes = (freeclust * spc)/1024 * bps;      LabelFreeSpace->Caption = AnsiString(FormatSize(free_bytes));      if (volsize > 0)          LabelUsed->Caption = AnsiString(((volsize - free_bytes) * 100) / volsize) + " %";      else          LabelUsed->Caption = "n/a";  }  //--------------------------------------------------------------------------- void __fastcall TFormSystemService::DriveComboBox1Change(TObject *Sender)  {    ButtonGetDriveInfoClick(Sender);  }  //--------------------------------------------------------------------------- void __fastcall TFormSystemService::ButtonChangeVolumeLabelClick(TObject *Sender)  {    AnsiString Drive = AnsiString(DriveComboBox1->Drive) + ":\"; //EditDrive->Text;    bool success = SetVolumeLabel(                          Drive.c_str(),                          EditVolumeInfo->Text.c_str());    if  (!success)        MessageBox(Handle,            "Unable to change volume label due to a system restriction.",            "System Restriction",MB_OK);    else        ButtonGetDriveInfoClick(Sender);  }  

In this example, the ButtonGetDriveInfoClick() event handler uses three primary Win32 API calls to gather disk information: GetDriveType() , GetVolumeInformation() , and GetDiskFreeSpace() .

GetDriveType() is simply used to determine the type of drive the user wants to examine. Options include removable, fixed, and remote drives as well as CD-ROM, which includes DVD drives , and RAM disks.

The GetVolumeInformation() provides even more revealing information including the volume label, serial number, maximum allowable filename length (called component length by Microsoft), and associated file system flags. The GetVolumeInformation() function has the following parameters:

 BOOL GetVolumeInformation(      LPCTSTR lpRootPathName,        // address of root directory of the file system      LPTSTR lpVolumeNameBuffer,    // address of name of the volume      DWORD nVolumeNameSize,        // length of lpVolumeNameBuffer      LPDWORD lpVolumeSerialNumber,    // address of volume serial number      LPDWORD lpMaximumComponentLength,// address of system's maximum filename length      LPDWORD lpFileSystemFlags,    // address of file system flags      LPTSTR lpFileSystemNameBuffer,    // address of name of file system      DWORD nFileSystemNameSize     // length of lpFileSystemNameBuffer     ); 

Each of these parameters that are returned by the GetVolumeInformation() function provide something of interest that we can display to the user. For developers, a value such as the lpVolumeSerialNumber could be found useful in supporting the licensing and registration of software.

Finally, GetDiskFreeSpace() is used to determine the size and available space on a drive. The GetDiskFreeSpace() function has the following parameters:

 BOOL GetDiskFreeSpace(      LPCTSTR lpRootPathName,    // address of root path      LPDWORD lpSectorsPerCluster,    // address of sectors per cluster      LPDWORD lpBytesPerSector,    // address of bytes per sector      LPDWORD lpNumberOfFreeClusters,    // address of number of free clusters      LPDWORD lpTotalNumberOfClusters     // address of total number of clusters     ); 

By using a little math, we can determine the volume size and the available free space in terms of bytes, which is a much more universally understood quantity than clusters. Multiplying the lpBytesPerSector and pSectorsPerCluster with the lpTotalNumberOfClusters for the volume size and the lpNumberOfFreeClusters for the available free space does this.

In this example, we also have code in ButtonChangeVolumeLabelClick() that can change the Volume label. This is accomplished using the SetVolumeLabel() API call.

File Information

Finally let's take a look at some code from this sample that uses the Win32 System Service calls to provide file information (see Listing 14.7). This information includes file type, attributes, size, and the date and time the file was last modified.

Listing 14.7 Windows System Service Utility ”Final Information Example
 void __fastcall TFormSystemService::ButtonGetFileInfoClick(TObject *Sender)  {    if(OpenDialog1->Execute())    {        EditFilename->Text = ExtractFileName(OpenDialog1->FileName);        LabelLocation->Caption = ExtractFilePath(OpenDialog1->FileName);        // clear out everything        LabelAttrib->Caption = "";        LabelFileID->Caption = "";        LabelDateTime->Caption = "";        // let's open the file        HANDLE FileHandle = CreateFile(OpenDialog1->FileName.c_str(),                GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);        if (FileHandle == INVALID_HANDLE_VALUE)        {            MessageBox(Handle, OpenDialog1->FileName.c_str(),                            "Unable to open file", MB_ICONSTOP  IDOK);            return;        }        else // // get file type        {           DWORD FileType = GetFileType(FileHandle);           switch (FileType)           {               case FILE_TYPE_DISK:                    LabelFileType->Caption = "Disk File";                    break;               case FILE_TYPE_CHAR:                    LabelFileType->Caption = "Character";                    return;  // can't do much else               case FILE_TYPE_PIPE:                    LabelFileType->Caption = "Anonymous Pipe";                    return;  // can't do much else               default : LabelFileType->Caption = "Unknown";           }        }  // get more information        BY_HANDLE_FILE_INFORMATION FileInfo;        GetFileInformationByHandle(FileHandle, &FileInfo);        AnsiString temp;        if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)                temp += "Archive ";        if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED)                temp += "Compressed ";        if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)                temp += "Directory ";        if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)                temp += "Hidden ";        if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_NORMAL)                temp += "Normal ";        if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE)                temp += "Offline ";        if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY)                temp += "Readonly ";        if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)                temp += "System ";        if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY)                temp += "Temporary Storage ";        LabelAttrib->Caption = temp;        char string1[35];        char string2[35];        sprintf(string1,"%08X",FileInfo.nFileIndexHigh);        sprintf(string2,"%08X",FileInfo.nFileIndexLow);        LabelFileID->Caption = "0x" + AnsiString(string1) + AnsiString(string2); //hex        LabelFileSize->Caption =  FormatSize(double(FileInfo.nFileSizeLow / 1024.0));        SYSTEMTIME SysTime;  // system time and date        FileTimeToSystemTime(&FileInfo.ftLastWriteTime, &SysTime);        char date[255];        char time[255];        sprintf(date,"%u/%u/%4u",            SysTime.wMonth, SysTime.wDay, SysTime.wYear);        sprintf(time,"%2u:%02u.%02u",            SysTime.wHour, SysTime.wMinute, SysTime.wSecond);        LabelDateTime->Caption = AnsiString(date) + " " + AnsiString(time);        CloseHandle(FileHandle);    }  }  

The first Win32 API call made in the ButtonGetFileInfoClick() event handler routine is CreateFile() . CreateFile() can be used for creating or opening the following types of objects:

  • files

  • pipes

  • mailslots

  • communications resources

  • disk devices (Windows NT only)

  • consoles

  • directories (open only)

In this example, CreateFile() is used to obtain a handle to a common file, which will be examined using other API calls within the event handler. The parameters of interest passed into CreateFile() include the filename, which was obtained through Borland's TOpenDialog , a desired access of read-only established through the GENERIC_READ flag, and an action to open an existing file through the OPEN_EXISTING flag.

After the file handle is obtained, a call is made to the Win32 API routine GetFileType() with the handle, which subsequently returns the type of file to be examined. File types include disk file, character, or an anonymous pipe. We're interested in the disk files in this example.

GetFileInformationByHandle() is then used to retrieve the bulk of the file information desired. The GetFileInformationByHandle() function has the following parameters:

 BOOL GetFileInformationByHandle(      HANDLE hFile,     // handle of file      LPBY_HANDLE_FILE_INFORMATION lpFileInformation // address of structure     ); 

The second parameter, which points to a variable defined by the LPBY_HANDLE_FILE_INFORMATION , is key for capturing the file information.

Let's take a look at the LPBY_HANDLE_FILE_INFORMATION structure.

 typedef struct _BY_HANDLE_FILE_INFORMATION { // bhfi      DWORD    dwFileAttributes;      FILETIME ftCreationTime;      FILETIME ftLastAccessTime;      FILETIME ftLastWriteTime;      DWORD    dwVolumeSerialNumber;      DWORD    nFileSizeHigh;      DWORD    nFileSizeLow;      DWORD    nNumberOfLinks;      DWORD    nFileIndexHigh;      DWORD    nFileIndexLow;  } BY_HANDLE_FILE_INFORMATION; 

For this example, the properties of interest provided include dwFileAttributes for obtaining the attributes, nFileIndexHigh and nFileIndexLow for determining the file ID, nFileSizeLow for determining the file size, and ftLastWriteTime for determining the file modification date and time.

Finally, it's important to clean up properly by closing the file handle that we've examined. This is accomplished through the CloseHandle() Win32 API routine.

NOTE

We can also obtain the file size using the Win32 API routine GetFileSize() , which returns the file size as an integer. GetFileSize() is declared as follows:

 DWORD GetFileSize(    HANDLE hFile,           // handle to file    LPDWORD lpFileSizeHigh  // high-order word of file size  ); 

You might be asking, "If GetFileSize() returns the file size, what is the second parameter lpFileSizeHigh for?" Well, back in the early days of Windows development Microsoft apparently had the foresight to recognize that a single file could eventually get really, really big. In this case, bigger than four gigabytes (GB), since the largest value an unsigned 32-bit integer could represent is 4,294,967,296 (2^32 bytes). So, for those really big files that are greater than four (GB), the Windows API provides another 32-bit word (called the high-order word) that catches the overflow. If you do the math, you'll realize that Windows is designed to support files up to 17,179,869,184GB (2^64 bytes) in size. Of course, make sure your hard drive is big enough, before creating a file of that magnitude. Seriously though, you can normally leave the second parameter as null because most files today are well less than four GB low-order value. But in the future, who knows , we might be requiring that high-order word support for obtaining the file size.


Spawning Applications and Discovering Window Handles

Microsoft's recommended way to launch an application within Windows is to use the CreateProcess() method. Although it might be recommended, you should be forewarned that it's the most difficult. It does, however, provide some distinct advantages over other methods .

Suppose that within an application it's necessary to not only launch (spawn) other applications, but also manage them (as we demonstrated in the Windows Management example earlier). For example, suppose when the main application is minimized, all other applications might need to be minimized as well. Or, when the main application is closed, any other applications that were spawned need to be closed as well. To support these specialized window management responsibilities, it is important to determine (or discover) a handle of another application. The knowledge of a target's application handle enables either standard Windows messages or custom Windows messages to be passed between applications. The CreateProcess() function can be used to facilitate the retrieval of an application's handle. The following code snippet shows one way of executing an application and retrieving its application handle:

 void __fastcall TFormWinMan::ButtonLaunchAppClick(TObject *Sender)  {     if (ListBoxApps->ItemIndex >=  0) {        char * data = (char*)ListBoxApps->Items->Objects[ListBoxApps->ItemIndex];        AnsiString fullfilename  = AnsiString(data);        EditFullFileName->Text = fullfilename;        EditWHandle->Text = "0";        winhandle = 0;        processid =  0;        STARTUPINFO  StartupInfo;        ZeroMemory( &StartupInfo, sizeof(STARTUPINFO));        PROCESS_INFORMATION ProcessInfo;        StartupInfo.cb = sizeof(STARTUPINFO);        if(CreateProcess(file,       // Windows System Service Call            parameters,            NULL,            NULL,            TRUE,            NORMAL_PRIORITY_CLASS,            NULL,            NULL,            &StartupInfo,            &ProcessInfo))        {            // We must close the handles returned in ProcessInfo. We can            // close the handle at any time, might as well close it now            CloseHandle(ProcessInfo.hProcess);     // Windows System Service Call            CloseHandle(ProcessInfo.hThread);      // Windows System Service Call            processid =  (unsigned long)ProcessInfo.dwProcessId;        }       if (processid != 0)            TimerGetHandle->Enabled = true; // use timer to get handle       SetForegroundWindow(Handle);     }  }  //--------------------------------------------------------------------------- void __fastcall TFormWinMan::TimerGetHandleTimer(TObject *Sender)  {     if (processid != 0)     {         winhandle = LookForWindowHandle(processid);         if (winhandle != NULL)         {              TimerGetHandle->Enabled = false;              UpdateAppInfo(winhandle);         }     }  }  //--------------------------------------------------------------------------- HWND TFormWinMan::LookForWindowHandle(unsigned long processid)  {      if (!EnumWindows((WNDENUMPROC)GetWinHandle_Specific,processid))          return swProcess;      else          return 0;  }  //--------------------------------------------------------------------------- BOOL CALLBACK TFormWinMan::GetWinHandle_Specific(HWND hwnd, unsigned long hproc)  {      unsigned long dwProcessId; // address of variable for process identifier      GetWindowThreadProcessId(          hwnd,          &dwProcessId);        // address of variable for process identifier      if (dwProcessId != hproc)  return true;    // keep enumerating      char windowtitle[80];      char classname[80];      GetWindowText( hwnd, windowtitle, 80);      if (windowtitle[0] == NULL) return true;      GetClassName(hwnd, classname, 80);      int ptr = strcmp(classname, "TApplication");      if (ptr == 0) return true;      FormWinMan->swProcess=hwnd;      return false; //stop enumeration  } 

In ButtonLaunchAppClick() event handler, we use the CreateProcess() call to launch an external application and obtain the process ID for that application. After we clean up some unneeded information through the CloseHandle() Win32 API call, we immediately start a timer, which calls a custom-function created for this example called LookForWindowHandle() . LookForWindowHandle() iterates through the list of active applications and performs a process ID match. When a match is found, the application's handle can then be obtained. Both of these functions encapsulate several Win32 API calls from various functional areas and are described in detail in the following paragraphs.

Let's step back for a moment and look at the CreateProcess() call used in the ButtonLaunchAppClick() event handler. Appropriately named, the CreateProcess() function creates a new application process and its execution thread by launching the specified executable file. StartUpInfo is a variable passed into the CreateProcess() function that specifies how the main window for the new application will appear. StartUpInfo is initialized using the ZeroMemory() Win32 function, which simply fills the structure with zeros. StartUpInfo is defined by the STARTUPINFO structure, as described in the Win32 API Help reference.

CreateProcess() fills in the ProcessInfo variable with information about the newly created process, and its primary thread. ProcessInfo is defined by the PROCESS_INFORMATION structure shown in the following:

 typedef struct _PROCESS_INFORMATION  {      HANDLE hProcess;      HANDLE hThread;      DWORD dwProcessId;      DWORD dwThreadId;  } PROCESS_INFORMATION; 

The process ID returned by the CreateProcess() function is actually extracted from the dwProcessId field of the structure. In the example we keep track of the process ID, and kickoff the TimerGetHandle timer. The TimerGetHandleTimer() event handler will then call LookForWindowHandle() each interval and pass the process ID as a parameter.

The process ID aides in determining the Windows handle of the spawned application through the LookForWindowHandle() function.

LookForWindowHandle() is a custom function that uses the Win32 EnumWindows() function. As discussed in the Windows Management section, EnumWindows() enumerates through all the top-level windows by utilizing a custom callback function. In this example the callback faction is called GetWinHandle_Specific() .

GetWinHandle_Specific() stakes in each enumerated handle and the processed ID that we're trying to find a match. It gathers other information regarding the window handle using various Win32 Windows Management API calls. When a match is found the callback returns false , and the enumeration process halts returning the handle of the application that we spawned. The timer then populates the display with information regarding the spawned application and is disabled.


     
Top


C++ Builder Developers Guide
C++Builder 5 Developers Guide
ISBN: 0672319721
EAN: 2147483647
Year: 2002
Pages: 253

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net