- Table of contents
- FileMapping - v2.0.0
- Quick start
- AutoHotkey.com link
- Reddit link
- New in v2.0.0
- Inter-process communication
- Using a file path
- Views and pages
- Encoding
- Options
- Methods
- Properties
- Global functions
- FileMapping_SystemTime and FileMapping_FileTime
- src\SecurityAttributes.ahk
- Changelog
- Table of contents generated by Headers2ToC.ahk
FileMapping is a class that provides a familiar AHK wrapper around the Windows API
file mapping object.
A file mapping object behaves similarly to a regular file (like a text file), but instead of the data
being located on the hard drive, the data is located entirely in memory. The primary reasons you might decide to
use a FileMapping object are:
- Read / write operations are much faster.
- The object can be accessed by multiple processes, allowing external processes to share information.
- Data can be accessed incrementally, avoiding the need for reading large amounts of data into memory all at once.
The methods are designed to work similarly to AHK's native File.
In general use cases, the code for using a FileMapping object will look nearly identical to the
code for using a File object.
File object:
f := FileOpen("MyFile.Txt", "rw", "UTF-16")
OutputDebug(f.Read() "`n")
f.Write("`nAnother line.")
f.Pos := 2
OutputDebug(f.Read() "`n")
f.Close()FileMapping object:
#include <FileMapping>
fm := FileMapping({ Path: "MyFile.Txt", Encoding: "UTF-16" })
fm.Open()
OutputDebug(fm.Read() "`n")
fm.Write("`nAnother line.")
fm.Pos := 2
OutputDebug(fm.Read() "`n")
fm.Close()The following is a brief introduction intended to share enough information for you to make use of this library. Run the demo files test\demo-ipc-1.ahk and test\demo-ipc-2.ahk for a working example of how to use the library for inter-process communication.
- Clone the repository.
git clone https://github.com/Nich-Cebolla/AutoHotkey-FileMapping- Copy FileMapping.ahk to your lib folder.
xcopy C:\users\you\path\to\AutoHotkey-FileMapping\src\FileMapping.ahk %USERPROFILE%\documents\AutoHotkey\lib\FileMapping.ahk- Include the library in your script.
#include <FileMapping>- Use the object
- Create a blank file mapping object:
fm := FileMapping() fm.Open() fm.Write("Hello, world!")
- Create a file mapping object backed by a file:
fm := FileMapping({ Path: "MyFile.txt" }) fm.Open() OutputDebug(fm.Read() "`n")
https://www.autohotkey.com/boards/viewtopic.php?f=83&t=139618&p=612492#p612492
v2.0.0 introduces many new methods, and has two small breaking changes.
FileMapping.Prototype.Cut- Makes a copy of a string, and moves the remaining data to the left, overwriting the string. Effectively removes a string from the data.FileMapping.Prototype.Cut2- Same as Cut by using a VarRef parameter.FileMapping.Prototype.CutEx- Makes a copy of a string using a RegEx pattern to specify the end point of the string, and moves the remaining data to the left, overwriting the string. Effectively removes a string from the data.FileMapping.Prototype.Insert- Inserts a string into the data, shifting the data to the right to make room for the inserted characters.FileMapping.Prototype.Insert2- Same as Insert but using a VarRef parameter.FileMapping.Prototype.InsertEx- Similar to Insert, but the way the function detemines what data to move is handled internally. InsertEx finds the first null terminator after the file pointer's current position, and shifts the data between the file pointer's current position and the first null terminator to the right, allowing the string to be inserted without overwriting anything. This is beneficial for use case scenarios where a certain amount of space in the file mapping object is allotted for object members or items in a structured dataset.FileMapping.Prototype.RawCut- Similar to Cut, but manipulates raw data instead of strings.FileMapping.Prototype.RawInsert- Similar to Insert, but manipulates raw data instead of strings.FileMapping.Prototype.RawReplace- Similar to Replace, but manipulates raw data instead of strings.FileMapping.Prototype.Read3- Similar to Read2, the difference being that the string is appended to the VarRef instead of assigned to it.FileMapping.Prototype.Replace- Ovewrites a specified string with another string, shifting the data to the right of the replaced string either right or left, depending on the relative size of the replacement string compared to the size of the string that was replaced.FileMapping.Prototype.TerminateEx- Similar to Terminate, but allows the null terminator to be written at a specified offset, instead of at the current position.
Originally, FileMapping.Prototype.Terminate moved the file pointer to just after the null terminator.
Now, FileMapping.Prototype.Terminate does not move the file pointer. It is assumed that, if more
is to be added to the string data, the null terminator should be overwritten, and so this is the more
optimal approach. To migrate code from v1 to v2, adjust any calculations that expect
FileMapping.Prototype.Terminate to move the file pointer past the null terminator.
FileMapping.Prototype.__Enum now caches the original view's size and start page, and returns the
view to the original state after the enumeration completes. This change was necessary to avoid
execution problems when running code in a debugger. Previously, if the debugger evaluated the
enumerator, it would alter the property values of the FileMapping object, resulting in invalid
code execution. By returning the view to its original state, this issue is avoided. To migrate code
from v1 to v2, adjust the code which follows an object enumeration to account for the fact that the
view is returned to its original state.
Inter-process communication (IPC) is when two external processes intentionally communicate with one
another to share information or influence behavior. There are many ways to facilitate IPC, one of
which is through the use of a FileMapping object.
Run the demo files test\demo-ipc-1.ahk and test\demo-ipc-2.ahk to see how simple it is to use a
file mapping object to share information between scripts. All that is needed is for both scripts
to set Options.Name with the same name, and when the second script opens the file mapping object,
the operating system will provide a handle to the same object that is opened in the first script.
Synchronization is not necessary;
"Coherency is guaranteed for views within a process and for views that are mapped by different processes.".
For more information about Options.Name, see Options and see the documentation for
paramter lpName.
You don't need to use any special options to use a FileMapping object for IPC. Just ensure that
Options.Name is the same for any script you want to have access to the object, and that's it.
File mapping objects exist in memory; they are not automatically associated with a file on disk.
If you set Options.Path with a valid path to a file, FileMapping will create the file mapping
object backed by the file located at the path. When a view is opened, the view will contain the data
from that file. To save the data back to the file, your code calls FileMapping.Prototype.Flush.
The FileMapping class does not require you to have an actual file to use with the class. Creating
a FileMapping object without a path is a valid use case scenario. When the file mapping object
is not backed by a file on disk, it is backed by the system's pagefile. I included method
FileMapping.Prototype.ToFile which will write the data to a file.
After creating the file mapping object (with the Windows API function CreateFileMappingW), we must
also open a view. The FileMapping library includes two general approaches for opening a view -
opening a specified number of bytes, or opening a specified number of pages.
When you open a view, it determines what data is accessible from the file mapping object. A view must be opened to a byte offset that is a multiple of the system's virtual memory allocation granularity, or 1 page. The methods that open a view handle this alignment for you, and moves the file pointer to the location indicated by your input parameters so you do not need to do any extra work to use the object. With this in mind, your main considerations when opening a view are:
- Where should the view start at?
- How big should the view be?
If your starting point does not align with the system's requirements, the library adjusts it for you and moves the file pointer to the starting position instead.
As you read from and write to the object, the library moves the file pointer accordingly. If you
reach the end of a view, as long as there is more space remaining (i.e. the object is not opened
to the limit set by Options.MaxSize) the library seamlessly extends the view to a size large enough
to complete the read / write operation.
If your object does happen to reach its limit (Options.MaxSize), write operations have a parameter
AdjustMaxSize which, if nonzero, will cause the library to double the maximum size of the object
automatically.
In most cases, you can simply not set any parameters to allow the library to open the entire object so all the data can be available at once. But, when working with very large data, you can open views to a limited range to minimize concurrent memory usage.
The library considers one page to be equivalent to the system's virtual memory allocation granularity, typically 65536 bytes. I included the page system to make it easier to work with the API's alignment requirements, but you do not need to think or worry about what they mean or how they impact the code, because the library handles all of that internally.
For large data, you can enumerate a file mapping object's pages by calling the object in a for
loop. You can see a number of examples of this in the test file test\test.ahk, but below is a short
example.
fm := FileMapping({ Path: "MyLargeData.csv", Encoding: "utf-8" })
str := ''
for page, offset, bytes, isLastIteration in fm {
; By the end of the loop, `str` will contain the entire data
str .= fm.Read()
; do other work
}You can also use a regular loop and call FileMapping.Prototype.NextPage, which will return 0 when
the last page has already been reached.
fm := FileMapping({ Path: "MyLargeData.csv", Encoding: "utf-8" })
fm.OpenP(0, 1)
str := ''
loop {
str .= fm.Read()
; do work
if !fm.NextPage(1) {
break
}
}You can use FileMapping with any encoding supported by AHK's StrPut and StrGet functions. The
methods have been thoroughly tested using UTF-8 (cp65001) and UTF-16 (cp1200), but are expected
to be compatible with any encoding except FileMapping.Prototype.SeekToBeginning.
FileMapping.Prototype.SeekToBeginning can be used to move the file pointer to the beginning of
a view, accounting for the byte order mark (BOM) when a view is opened to the beginning of the object.
In most cases FileMapping.Prototype.SeekToBeginning moves the file mapping object's file pointer
to 0. But if the following conditions are all true, it moves the position to just after the BOM:
- The encoding is UTF-8 or UTF-16
- The page is 0
- There is a BOM
FileMapping.Prototype.SeekToBeginning is a convenience feature to take the hassle out of deciding
where the beginning of the content is, but it only knows about the BOM for UTF-8 and UTF-16.
Most of the options are associated with a parameter for one of CreateFileW, CreateFileMappingW, or MapViewOfFile.
Currently, FileMapping does not have the same convenience flags for opening a file with read / write
/ read+write access that are offered by the AHK FileOpen function. By default, all file mapping
objects are created with general read/write access. If you need to change this, you must set the
relevant property on the options object. Changing read / write access involves multiple properties,
since each of the Windows API functions have a parameter related to access level.
For the Windows API constants, you can refer to them by name (e.g. GENERAL_READ, OPEN_ALWAYS).
If your code encounters a var unset error, call FileMapping_SetConstants() anywhere before you use
the variable.
Apart from the options that influence the access level used when creating the objects, the main options of interest are going to be:
{String} [ Options.Encoding = "utf-16" ] - The file encoding used when reading from and
writing to a view. The library is tested with both UTF-8 and UTF-16 encodings. Other encodings should
work without issue, however, some convenience features related to the BOM are only available for UTF-8
(cp65001) and UTF-16 (cp1200) encodings.
{Integer} [ Options.MaxSize = 0 ] - Use Options.MaxSize
to specify the maximum size of the file mapping object. If Options.Path is used, Options.MaxSize
should be greater than or equal to the size of the file. If Options.MaxSize is 0 and if Options.Path
is used, the maximum size of the file mapping object is equal to the current size of the file. If
Options.MaxSize is 0 and if Options.Path is not used, the libary sets the maximum size to
FileMapping_VirtualMemoryGranularity (1 page).
{String} [ Options.Name ] - The name of the file mapping object. Set Options.Name when
using FileMapping for inter-process communication.
When creating a file mapping object, the name must be unique across the system. If the name is
already in use, and the name is associated with an existing file mapping object,
CreateFileMapping requests a handle to the existing file mapping object instead of creating
a new object. If the name exists but is some other type of object, the function fails.
To direct FileMapping.Prototype.__New to generate a random name, set Options.Name
with any string that ends with a backslash optionally followed by a number representing the
number of characters to include in the name. Your code can begin the string with any valid
string to use as a prefix, and the random characters will be appended to the prefix. For
example, each of the following are valid for producing a random name:
- "\" - generates a random name of 16 characters.
- "\20" - generates a random name of 20 characters.
- "Global\\22" - generates a random name of 22 characters and appends it to "Global\".
- "Local\\" - generates a random name of 16 characters and appends it to "Local\".
- "Local\MyAppName_\" - generates a random name of 16 characters and appends it to "Local\MyAppName_".
- "MyAppName\14" - generates a random name of 14 characters and appends it to "MyAppName".
- "Global\Ajmz(eOO\10" - generates a random name of 10 characters and appends it to "Global\Ajmz(eOO".
The random characters fall between code points 33 - 91, inclusive. If your application requires
a different set of characters to be used, leave Options.Name unset and call
FileMapping.Prototype.SetName before opening the file mapping object.
When FileMapping.Prototype.SetName generates the random name, it overwrites the
value of the property "Name" on the options object. Accessing FileMapping.Prototype.Name
will return the new name.
Using a random name has the benefit of preventing a scenario where a bad-actor blocks your application from functioning intentionally by preemptively creating an object with a name known to be used by your application. It is also helpful for avoiding a scenario where your application attempts to use the same name as another application coincidentally.
See https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingw for more info.
{String} [ Options.Path ] - If the FileMapping object is being used to map a file,
the path to the file. See Using a file path for more info.
{Boolean} [ Options.SetOnExit = true ] - This option determines whether or not the
built-in OnExit callback, which safely closes an opened file object and/or file mapping
object, is toggled whenever a file / file mapping object is opened and closed.
The value of Options.SetOnExit is passed to the AddRemove parameter of
OnExit.
When Options.SetOnExit is nonzero, FileMapping.Prototype.SetOnExitCallback is called
within the body of the following methods:
FileMapping.Prototype.OpenFileMapping.Prototype.OpenFileFileMapping.Prototype.OpenMappingFileMapping.Prototype.OpenP
When this option is nonzero, an OnExit callback is set whenever a file object is created
and whenever a file mapping object is created. The callback closes the objects safely before
the script exits. The OnExit callback is automatically disabled when both the file object
and file mapping object handles have been closed. This occurs within the body of:
FileMapping.Prototype.CloseFileMapping.Prototype.CloseFileFileMapping.Prototype.CloseMapping
{Integer} [ Options.dwCreationDisposition = OPEN_EXISTING ] - The action to take on a file
or device that exists or doesn't exist.
- CREATE_ALWAYS
- CREATE_NEW
- OPEN_ALWAYS
- OPEN_EXISTING
- TRUNCATE_EXISTING
See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew for more info.
{Integer} [ Options.dwDesiredAccess_file = GENERIC_READWRITE ] - The access to the file.
One or more of:
- GENERIC_ALL
- GENERIC_EXECUTE
- GENERIC_WRITE
- GENERIC_READ
- GENERIC_READWRITE
See https://learn.microsoft.com/en-us/windows/win32/secauthz/generic-access-rights and https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew for more info.
{Integer} [ Options.dwDesiredAccess_view = FILE_MAP_ALL_ACCESS ] - The page protection for the
file mapping object.
- One or more of these:
- FILE_MAP_ALL_ACCESS
- FILE_MAP_READ
- FILE_MAP_WRITE
- Can be combined with these using bit-wise or ( | )
- FILE_MAP_COPY
- FILE_MAP_EXECUTE
- FILE_MAP_LARGE_PAGES
- FILE_MAP_TARGETS_INVALID
See https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapviewoffile for more info.
{Integer} [ Options.dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL ] - The file or device
attributes and flags. One or more of:
- FILE_ATTRIBUTE_ARCHIVE
- FILE_ATTRIBUTE_ENCRYPTED
- FILE_ATTRIBUTE_HIDDEN
- FILE_ATTRIBUTE_NORMAL
- FILE_ATTRIBUTE_OFFLINE
- FILE_ATTRIBUTE_READONLY
- FILE_ATTRIBUTE_SYSTEM
- FILE_ATTRIBUTE_TEMPORARY
- FILE_FLAG_BACKUP_SEMANTICS
- FILE_FLAG_DELETE_ON_CLOSE
- FILE_FLAG_NO_BUFFERING
- FILE_FLAG_OPEN_NO_RECALL
- FILE_FLAG_OPEN_REPARSE_POINT
- FILE_FLAG_OVERLAPPED
- FILE_FLAG_POSIX_SEMANTICS
- FILE_FLAG_RANDOM_ACCESS
- FILE_FLAG_SESSION_AWARE
- FILE_FLAG_SEQUENTIAL_SCAN
- FILE_FLAG_WRITE_THROUGH
See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew for more info.
{Integer} [ Options.dwShareMode = FILE_SHARE_WRITE | FILE_SHARE_READ ] - The share mode
of the file. One or more of:
- FILE_SHARE_DELETE
- FILE_SHARE_READ
- FILE_SHARE_WRITE
See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
{Integer} [ Options.flProtect = PAGE_READWRITE ] - The protection to apply to the file mapping object.
- One of the following:
- PAGE_EXECUTE_READ
- PAGE_EXECUTE_READWRITE
- PAGE_EXECUTE_WRITECOPY
- PAGE_READONLY
- PAGE_READWRITE
- PAGE_WRITECOPY
- Combined with one or more of:
- SEC_COMMIT
- SEC_IMAGE
- SEC_IMAGE_NO_EXECUTE
- SEC_LARGE_PAGES
- SEC_NOCACHE
- SEC_RESERVE
- SEC_WRITECOMBINE
See https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingw for more info.
{Integer} [ Options.hTemplateFile = 0 ] - A handle to a template file with the same attributes as the file
mapping object. The file mapping object is created with the same attributes as the template file.
See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew for more info.
{Integer} [ Options.lpFileMappingAttributes = 0 ] - A pointer to a SECURITY_ATTRIBUTES structure
that contains the security descriptor for the file mapping object.
See https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingw for more info.
{Integer} [ Options.lpSecurityAttributes = 0 ] - A pointer to a SECURITY_ATTRIBUTES
structure that contains the security descriptor for the file object.
See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew for more info.
The following is a list of methods. The details are documented in the parameter hints in the code file. All methods are tested and working.
FileMapping.Prototype.AdjustMaxSizeFileMapping.Prototype.CalculateViewSizeFileMapping.Prototype.CloseFileMapping.Prototype.CloseFileFileMapping.Prototype.CloseMappingFileMapping.Prototype.CloseViewFileMapping.Prototype.CutFileMapping.Prototype.Cut2FileMapping.Prototype.CutExFileMapping.Prototype.ExtendViewFileMapping.Prototype.FlushFileMapping.Prototype.FlushFileBuffersFileMapping.Prototype.GetEncodingFileMapping.Prototype.InsertFileMapping.Prototype.Insert2FileMapping.Prototype.InsertExFileMapping.Prototype.NextPageFileMapping.Prototype.OpenFileMapping.Prototype.OpenPFileMapping.Prototype.OpenFileFileMapping.Prototype.OpenMappingFileMapping.Prototype.OpenViewFileMapping.Prototype.OpenViewPFileMapping.Prototype.RawCutFileMapping.Prototype.RawInsertFileMapping.Prototype.RawReadFileMapping.Prototype.RawReplaceFileMapping.Prototype.RawWriteFileMapping.Prototype.ReadFileMapping.Prototype.Read2FileMapping.Prototype.Read3FileMapping.Prototype.ReloadFileMapping.Prototype.ReplaceFileMapping.Prototype.SeekFileMapping.Prototype.SeekToBeginningFileMapping.Prototype.SetEncodingFileMapping.Prototype.SetEnumPageCountFileMapping.Prototype.SetFileTimeFileMapping.Prototype.SetNameFileMapping.Prototype.SetOnExitCallbackFileMapping.Prototype.TerminateFileMapping.Prototype.TerminateExFileMapping.Prototype.ToFileFileMapping.Prototype.UpdateFileTimeFileMapping.Prototype.WriteFileMapping.Prototype.Write2FileMapping.Prototype.__Enum
The following is a list of properties. The dynamic properties are documented in the code file. The value properties are documented here.
- {Integer}
BytesPerChar- Returns the number of bytes per character as determined byOptions.Encoding. - {Integer}
EnumPageCount- If set, determines the number of pages that are opened at a time when enumerating the object's pages in aforloop. - {Integer}
idFileMapping- The object's unique identifier. - {Integer}
Page- The page number of the start of the currently active view. - {Integer}
StartByte- The start byte of the file mapping object's contents. When there is a UTF-8 BOM, this is 3. When there is a UTF-16 (cp1200) BOM, this is 2. In all other cases it is 0.
FileMapping.Prototype.AtEoVFileMapping.Prototype.AtEoFFileMapping.Prototype.dwCreationDispositionFileMapping.Prototype.dwDesiredAccess_fileFileMapping.Prototype.dwDesiredAccess_viewFileMapping.Prototype.dwFlagsAndAttributesFileMapping.Prototype.dwMaximumSizeHighFileMapping.Prototype.dwMaximumSizeLowFileMapping.Prototype.dwShareModeFileMapping.Prototype.EncodingFileMapping.Prototype.flProtectFileMapping.Prototype.hTemplateFileFileMapping.Prototype.LastPageSizeFileMapping.Prototype.lpFileMappingAttributesFileMapping.Prototype.lpSecurityAttributesFileMapping.Prototype.MaxSizeFileMapping.Prototype.NameFileMapping.Prototype.OnExitActiveFileMapping.Prototype.OnLastPageFileMapping.Prototype.PagesFileMapping.Prototype.PathFileMapping.Prototype.PosFileMapping.Prototype.SetOnExitFileMapping.Prototype.TotalPagesFileMapping.Prototype.TotalPosFileMapping.Prototype.ViewEndFileMapping.Prototype.ViewStart
The following functions are documented in the code file.
FileMapping_BytesToPagesFileMapping_HasBomFileMapping_PagesToBytesFileMapping_RoundUpToPageFileMapping_SetConstantsFileMapping_SystemTime_SetConstants
FileMapping_SystemTime is an AHK wrapper around the
SYSTEMTIME
structure and FileMapping_FileTime is an AHK wrapper around the
FILETIME structure.
Use them to update a file's time attributes with FileMapping.Prototype.SetFileTime.
There is an additional file src\SecurityAttributes.ahk which contains a class SecurityAttributes,
an AHK wrapper around the
SECURITY_ATTRIBUTES
structure. It is not #included in FileMapping.ahk; you will need to #include it separately if you
want to use it.
-
2025-12-05 - v2.0.1
- Change:
- test\test.ahk - Updated tests to evaluate both utf-8 and utf-16 encodings.
- Change:
-
2025-12-05 - v2.0.0
- Release version 2.0.0. See New in v2.0.0.
-
2025-11-25 - v1.0.0
- Release version 1.0.0
-
2025-05-21
- I corrected an error in my documentation regarding opening a file mapping for IPC. I previously wrote that one should name the file mapping object with the "Global" prefix, but "Local" requires lower access.
- I corrected an error that caused opening the file mapping object to fail when using the
Nameparameter instead of thePathparameter. - I added basic writing support with the
FileMapping.Prototype.Writemethod. - Verified the class can be used for inter-process communication.
- Wrote "test-ipc.ahk".