10. Objects and Their Handles

Page 150
  10. Objects and Their Handles  
   
  Windows is full of objects. A kernel object is a data structure whose members are accessible only by the Windows kernel. Examples of kernel objects are:  
 
  Process object
Represents a process
 
 
  Thread object
Represents a thread
 
 
  File object
Represents an open file
 
 
  File-mapping object
Represents a memory-mapped file, that is, a file whose contents are directly mapped to virtual memory addresses and used like physical memory
 
 
  Pipe object
Used to send data between processes
 
 
  Event object
A thread synchronization object used to signal when an operation has completed
 
 
  Mutex object
A thread synchronization object that can be used across multiple processes
 
 
  Semaphore object
Used for resource counting, to signal a thread when a resource is available
 
   
  In addition to kernel objects, there are also user objects and GDI objects, such as menus, windows, fonts, brushes, and mouse cursors.  
Page 151
 
  Handles  
   
  One of the characteristics of an object is that it has a handle that is used to identify it.  
   
  Although kernel objects are not directly accessible from user mode, the Windows API provides user-mode functions for manipulating these objects. This is a form of encapsulation that protects the objects from unwarranted tampering. When a kernel object is created through a call to the appropriate API function (such as CreateProcess, CreateThread, CreateFile, and CreateFileMapping), the function will return the newly created object's handle, which can then be passed to other API functions in order to manipulate the object.  
   
  Generally speaking, an object handle is process-specific, which means that it is only valid within a given process. On the other hand, some identifiers, such as process IDs, are system-wide, which means they are valid throughout all processes. We will have occasion to use both process handles and process IDs from time to time.  
   
  Usage Counts  
   
  Kernel objects are owned by the Windows kernel, not by the process that created the object (or any other process). As we will see, objects can be shared by multiple processes in a variety of ways. Each process that uses an object has its own process-specific handle to that object.  
   
  In view of this, the kernel must maintain a usage count for each object. When that count reaches 0, the kernel will destroy the object, but not before. In this way, the process that created an object can close its handle (by calling the CloseHandle API function), but the object will not be destroyed if some other process currently has a handle to the object.  
   
  We note also that kernel objects have security attributes that can be used to restrict access to the object. In fact, this is one of the main features that distinguishes kernel objects from user and GDI objects.  
   
  Object Sharing Across Process Boundaries  
   
  There are several ways in which an object can be shared among processes:  
   
  Inheritance  
   
  When a process (that is, a thread within the process) creates a kernel object, it can specify that the object's handle be inheritable to child processes that the parent  
Page 152
   
  process may subsequently create. In this case, the value of the child's handle is the same as the value of the parent's handle.  
   
  Handle duplication  
   
  The DuplicateHandle function is defined as:  
   BOOL DuplicateHandle(        HANDLE hSourceProcessHandle,    // handle to the source process        HANDLE hSourceHandle,           // handle to duplicate        HANDLE hTargetProcessHandle,    // handle to process to duplicate to        LPHANDLE lpTargetHandle,        // pointer to duplicate handle        DWORD dwDesiredAccess,          // access for duplicate handle        BOOL bInheritHandle,            // handle inheritance flag        DWORD dwOptions                 // optional actions      );       
   
  This function allows a handle in one process to be duplicated into another process. The new process-relative handle in the target process may have a different value than the source handle, but this is of no concern since the handles are process-relative.  
   
  Named objects  
   
  Many kernel objects can be given a name when they are created. Names are valid system-wise, which means that any other process can access the object by using its name (assuming that it knows the name, of course). For instance, the last parameter in the CreateFileMapping function:  
 
  HANDLE CreateFileMapping(
   HANDLE hFile,                        // handle to file to map
   LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // optional security attributes
   DWORD flProtect,                     // protection for mapping object
   DWORD dwMaximumSizeHigh,             // high-order 32 bits of object size
   DWORD dwMaximumSizeLow,              // low-order 32 bits of object size
   LPCTSTR lpName                       // name of file-mapping object
);
 
   
  can be used to specify a name for the file mapping.  
   
  Assume, for instance, that we have created a file-mapping object named MyFMO. Another process can call OpenFileMapping with this name as its last argument. The function will return a process-relative handle to this object for use by the second process. Alternatively, the second process can call CreateFileMapping, using the object's name as its last argument. The system will see that a file-mapping object by this name already exists and simply return a handle to this object. (This does create a potential problem, because a process may think it is creating a new object when, in fact, it is getting a handle to an existing object. The programmer must check the return value of CreateFileMapping immediately to determine which is the case.)  
Page 153
 
  Example: File Mapping  
   
  Let us conclude this chapter with an example of creating, sharing, and destroying a kernel object. For this example, we will use the file-mapping object.  
   
  To put it simply, Windows is capable of treating a disk file as though it were part of memory. To do this, a portion of the file is mapped to a block of virtual memory addresses. Memory-related API functions such as CopyMemory can then be used to view and alter the disk file contents. When a file is mapped to memory in this way, the file is called a memory-mapped file.  
   
  Our application will do the following:  
   
  1. Create a file object, based on an existing file, using the CreateFile API function. This function will return a handle to the file object.  
   
  2. Use the file handle and the CreateFileMapping API function to create a filemapping object. The function returns a file-mapping object handle.  
   
  3. Use the file-mapping object handle and the MapViewOfFile API function to map a portion of the file to memory. This function assigns a block of virtual memory addressed to the file. The base address of this block is the handle for the file-mapping view.  
   
  4. Use the base address and the CopyMemory function to read the file and then write to the file. The program just toggles the case of the text of the sample file Mapped.txt.  
   
  5. Finally, close all handles.  
   
  Since the code from this example will be used in two VB applications (to demonstrate object sharing) and since you might want to use it in your own applications, the best place for it is in a class module. In fact, it is not difficult to create a class named CFileMapping with all of the necessary properties and methods for creating file objects, file-mapping objects, and memory-mapped views. Example 10-1 shows the entire code for the CFileMapping class.  
   
  Example 10-1. The CFileMapping Class  
   
  Option Explicit

Private mFileMappingName As String
Private mFileViewBase As Long
Private mFileMappingHandle As Long
Private mFileHandle As Long
Private mFileName As String

' ------------
' File mapping
' ------------
' Create a handle to console output
Private Declare Function CreateFile Lib  kernel32  _
 
Page 154
   
  Example 10-1. The CFileMapping Class (continued)  
   
     Alias  CreateFileA  ( _
   ByVal lpFileName As String, _
   ByVal dwDesiredAccess As Long, _
   ByVal dwShareMode As Long, _
   ByVal lpSecurityAttributes As Long, _
   ByVal dwCreationDisposition As Long, _
   ByVal dwFlagsAndAttributes As Long, _
   ByVal hTemplateFile As Long _
) As Long

Const GENERIC_READ = &H80000000
Const GENERIC_WRITE = &H40000000
Const FILE_SHARE_READ = &H1
Const FILE_SHARE_WRITE = &H2
Const OPEN_EXISTING = 3

Private Declare Function CreateFileMapping Lib  kernel32  _
   Alias  CreateFileMappingA  ( _
   ByVal hFile As Long, _
   ByVal lpSecurityAttributes As Long, _
   ByVal flProtect As Long, _
   ByVal dwMaximumSizeHigh As Long, _
   ByVal dwMaximumSizeLow As Long, _
   ByVal lpName As String _
) As Long

Const PAGE_NOACCESS = &H1
Const PAGE_READONLY = &H2
Const PAGE_READWRITE = &H4
Const PAGE_WRITECOPY = &H8
Const PAGE_EXECUTE = &H10
Const PAGE_EXECUTE_READ = &H20
Const PAGE_EXECUTE_READWRITE = &H40
Const PAGE_EXECUTE_WRITECOPY = &H80
Const PAGE_GUARD = &H100
Const PAGE_NOCACHE = &H200

Private Declare Function MapViewOfFile Lib  kernel32  ( _
   ByVal hFileMappingObject As Long, _
   ByVal dwDesiredAccess As Long, _
   ByVal dwFileOffsetHigh As Long, _
   ByVal dwFileOffsetLow As Long, _
   ByVal dwNumberOfBytesToMap As Long _
) As Long

Const SECTION_EXTEND_SIZE = &H10
Const SECTION_MAP_EXECUTE = &H8
Const SECTION_MAP_READ = &H4
Const SECTION_MAP_WRITE = &H2
Const SECTION_QUERY = &H1

Const FILE_MAP_COPY = SECTION_QUERY
Const FILE_MAP_READ = SECTION_MAP_READ
Const FILE_MAP_WRITE = SECTION_MAP_WRITE
 
Page 155
   
  Example 10-1. The CFileMapping Class (continued)  
   
  Private Declare Function CloseHandle Lib  kernel32  ( _
   ByVal hObject As Long) As Long
Private Declare Function UnMapViewOfFile Lib  kernel32  _
   Alias  UnmapViewOfFile  (ByVal lpBaseAddress As Long) As Long

Public Property Get FileMappingName() As String
   FileMappingName = mFileMappingName
End Property

Public Property Let FileMappingName(pFileMappingName As String)
   mFileMappingName = pFileMappingName
End Property

Public Property Get FileName() As String
   FileName = mFileName
End Property

Public Property Let FileName(pFileName As String)
   If Dir$ (pFileName, vbNormal) <>   Then
      mFileName = pFileName
   Else
      mFileName = 
   End If
End Property

Public Property Get FileHandle() As Long
   FileHandle = mFileHandle
End Property

Public Property Let FileHandle(pFileHandle As Long)
   mFileHandle = pFileHandle
End Property

Public Property Get FileMappingHandle() As Long
   FileMappingHandle = mFileMappingHandle
End Property

Public Property Let FileMappingHandle(pFileMappingHandle As Long)
   mFileMappingHandle = pFileMappingHandle
End Property

Public Property Get FileViewBase() As Long
   FileViewBase = mFileViewBase
End Property

Public Property Let FileViewBase(pFileViewBase As Long)
   mFileViewBase = pFileViewBase
End Property

Public Function OpenFile() As Long
' Opens file and gets file handle

mFileHandle = CreateFile(mFileName, _
 
Page 156
   
  Example 10-1. The CFileMapping Class (continued)  
   
     GENERIC_READ Or GENERIC_WRITE, _
   FILE_SHARE_READ Or FILE_SHARE_WRITE, _
   0&, _
   OPEN_EXISTING, 0&, 0&)

OpenFile = mFileHandle

End Function

Public Function OpenFileMapping() As Long

' Create file mapping
mFileMappingHandle = CreateFileMapping( _
   mFileHandle, 0&, PAGE_READWRITE, 0&, _
   FileLen(mFileName), mFileMappingName)
OpenFileMapping = mFileMappingHandle

End Function

Public Function MapFileView() As Long
mFileViewBase = MapViewOfFile( _
   mFileMappingHandle, FILE_MAP_WRITE, 0&, 0&, 0&)
MapFileView = mFileViewBase
End Function

Public Function ReadFromFile(cBytes As Long) As String
' Read from file mapping
ReDim bFile(1 To cBytes) As Byte
CopyMemory ByVal VarPtr(bFile(1)), ByVal mFileViewBase, cBytes
ReadFromFile = StrConv(bFile, vbUnicode)
End Function

Public Function WriteToFile(sWrite As String) As Long
' Return count of bytes written
Dim b() As Byte
Dim lpsz As Long
BSTRtoLPSTR sWrite, b, lpsz
CopyMemory ByVal mFileViewBase, ByVal lpsz, Len(sWrite)
WriteToFile = Len(sWrite)
End Function

Public Function UnMapFileView() As Long
UnMapFileView = UnMapViewOfFile(mFileViewBase)
End Function

Public Function CloseFileMapping() As Long
CloseFileMapping = CloseHandle(mFileMappingHandle)
End Function

Public Function CloseFile() As Long
CloseFile = CloseHandle(mFileHandle)
End Function
 
Page 157
   
  Note that several of the methods are just wrappers for the API function.  
   
  If you open the FileMapping project in the Code_Mapping subdirectory of the accompanying CD-ROM and press the command button, the following procedure will be executed. It assumes that the file Mapped.txt is in the application directory.  
 
  Sub DoFileMapping()

Dim sFileName As String
Dim s As String

' Create file
Dim oFile As New CFileMapping

' Set properties
oFile.FileName = App.Path & "\Mapped.txt"

If oFile.FileName = "" Then
   MsgBox App.Path & "\Mapped.txt does not exist", vbExclamation
   Exit Sub
End If

oFile.FileMappingName = "TestFileMapping"

List1.AddItem "Open file: " & oFile.OpenFile
List1.AddItem "Open file mapping: " & oFile.OpenFileMapping
List1.AddItem "Map file: " & oFile.MapFileView

' Read entire file
s = oFile.ReadFromFile(FileLen(oFile.FileName))
List1.AddItem "Read file: " & s

' Reverse case
If s = UCase$ (s) Then
   s = LCase$ (s)
Else
   s = UCase$ (s)
End If

List1.AddItem "Write file: " & oFile.WriteToFile(s) & " bytes"
List1.AddItem "Read file: " & oFile.ReadFromFile(FileLen(oFile.FileName))

List1.AddItem "UnMap file: " & oFile.UnMapFileView
List1.AddItem "Close file mapping: " & oFile.CloseFileMapping
List1.AddItem "Close file: " & oFile.CloseFile
List1.AddItem "
*****"
Set oFile = Nothing

End Sub
 
   
  The output is shown in Figure 10-1.  
   
  To see how two applications can share the same object in this case, a file object just place the CFileMapping class into two VB projects. Add the DoFileMapping subroutine to the projects and run them both.  
Page 158
   
  0158-01.gif  
   
  Figure 10-1.
The file-mapping application
 
   
  Coherence  
   
  Since we are on the subject of memory-mapped files, we should say a few more words about it. There is nothing to prevent the following from occurring to a single memory-mapped file:  
   
  Have multiple active views based on a single file-mapping object  
   
  Have several file-mapping objects based on the file, perhaps in different processes, each with its own views of the file  
   
  Have one process map a view of the file for writing while another process uses traditional file I/O functions on the file  
   
  Needless to say, these possibilities raise questions of what happens when one view changes the data in the file. Here are the facts:  
   
  If only a single file-mapping object is involved, even if that object is shared among different processes, the system will insure that all views based on that file-mapping object are coherent, that is, all views see the current state of the data, including any changes made through any of the views. This follows from the fact that all of these views see the same data, since it is stored in a single location in physical memory.  
   
  However, views of the file that are based on different file-mapping objects are not guaranteed to be coherent.  
   
  There is no guarantee that changes to a file made with traditional file I/O operations (ReadFile and WriteFile, for instance) will be reflected in file views.  
Page 159
   
  After all, these methods use memory buffers that are different from the buffers used by a file mapping. For this reason, we should not mix file-mapping techniques and memory-mapped techniques in the same process.  



WIN32 API Programming with Visual Basic
Win32 API Programming with Visual Basic
ISBN: 1565926315
EAN: 2147483647
Year: 1999
Pages: 31
Authors: Steven Roman

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