remove AWE code, and option from movie storage. add a new option for waterbox integrity checks, but it doesn't work yet because I can't get BH.Emulation.Common to build

This commit is contained in:
zeromus 2020-05-02 20:17:34 -04:00
parent e8e0a94d3e
commit 6a67a3320f
6 changed files with 684 additions and 1158 deletions

View File

@ -12,9 +12,6 @@ namespace BizHawk.Client.Common
{
public static bool DefaultToDisk { get; set; }
public static bool DefaultToAwe { get; set; }
/// <exception cref="InvalidOperationException"><see cref="DefaultToAwe"/> is <see langword="true"/> but not running on Windows host</exception>
public static IStringLog MakeStringLog()
{
if (DefaultToDisk)
@ -22,13 +19,6 @@ namespace BizHawk.Client.Common
return new StreamStringLog(true);
}
if (DefaultToAwe)
{
return OSTailoredCode.IsUnixHost
? throw new InvalidOperationException("logging to AWE is only available on Windows for now")
: new StreamStringLog(false);
}
return new ListStringLog();
}
@ -114,7 +104,8 @@ namespace BizHawk.Client.Common
}
else
{
_stream = new AWEMemoryStream();
//but leave this in case we want to retain the option for more efficient management than the list of strings
throw new InvalidOperationException("Not supported anymore");
}
_bw = new BinaryWriter(_stream);

View File

@ -121,7 +121,6 @@ namespace BizHawk.Client.EmuHawk
Global.Config.ResolveDefaults();
StringLogUtil.DefaultToDisk = Global.Config.MoviesOnDisk;
StringLogUtil.DefaultToAwe = Global.Config.MoviesInAwe;
// super hacky! this needs to be done first. still not worth the trouble to make this system fully proper
if (Array.Exists(args, arg => arg.StartsWith("--gdi", StringComparison.InvariantCultureIgnoreCase)))

File diff suppressed because it is too large Load Diff

View File

@ -86,7 +86,7 @@ namespace BizHawk.Client.EmuHawk
cbFrameAdvPastLag.Checked = _config.SkipLagFrame;
cbRunLuaDuringTurbo.Checked = _config.RunLuaDuringTurbo;
cbMoviesOnDisk.Checked = _config.MoviesOnDisk;
cbMoviesInAWE.Checked = _config.MoviesInAwe;
cbSkipWaterboxIntegrityChecks.Checked = _config.SkipWaterboxIntegrityChecks;
switch (_config.LuaEngine)
{
@ -127,7 +127,7 @@ namespace BizHawk.Client.EmuHawk
_config.SkipLagFrame = cbFrameAdvPastLag.Checked;
_config.RunLuaDuringTurbo = cbRunLuaDuringTurbo.Checked;
_config.MoviesOnDisk = cbMoviesOnDisk.Checked;
_config.MoviesInAwe = cbMoviesInAWE.Checked;
_config.SkipWaterboxIntegrityChecks = cbSkipWaterboxIntegrityChecks.Checked;
var prevLuaEngine = _config.LuaEngine;
_config.LuaEngine = grpLuaEngine.Tracker.GetSelectionTagAs<ELuaEngine>() ?? throw new InvalidOperationException();

View File

@ -1,123 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View File

@ -1,462 +0,0 @@
#nullable disable
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace BizHawk.Common
{
/// <summary>
/// A MemoryStream that uses AWE to achieve a large addressable area, without being subject to 32 bit address space limits.
/// </summary>
public class AWEMemoryStream : Stream
{
const int kBlockSizeBits = 20;
const int kBlockSize = 1 << 20;
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
[Flags]
enum MemoryProtection : uint
{
EXECUTE = 0x10,
EXECUTE_READ = 0x20,
EXECUTE_READWRITE = 0x40,
EXECUTE_WRITECOPY = 0x80,
NOACCESS = 0x01,
READONLY = 0x02,
READWRITE = 0x04,
WRITECOPY = 0x08,
GUARD_Modifierflag = 0x100,
NOCACHE_Modifierflag = 0x200,
WRITECOMBINE_Modifierflag = 0x400
}
[Flags]
enum AllocationType : uint
{
COMMIT = 0x1000,
RESERVE = 0x2000,
RESET = 0x80000,
LARGE_PAGES = 0x20000000,
PHYSICAL = 0x400000,
TOP_DOWN = 0x100000,
WRITE_WATCH = 0x200000
}
public AWEMemoryStream()
{
// bootstrap the datastructures
Position = 0;
// allocate the window (address space that we'll allocate physical pages into)
mWindow = VirtualAlloc(IntPtr.Zero, new IntPtr(kBlockSize), AllocationType.RESERVE | AllocationType.PHYSICAL, MemoryProtection.READWRITE);
}
protected override void Dispose(bool disposing)
{
if (mWindow != IntPtr.Zero)
{
VirtualFree(mWindow, IntPtr.Zero, 0x8000U); //MEM_RELEASE
mWindow = IntPtr.Zero;
}
if (disposing)
{
foreach (var block in mBlocks)
block.Dispose();
}
}
~AWEMemoryStream()
{
Dispose(false);
}
long mLength = 0, mPosition = -1;
long mCurrBlock = -1;
List<AWEMemoryBlock> mBlocks = new List<AWEMemoryBlock>();
IntPtr mWindow;
public override bool CanRead => true;
public override bool CanSeek => true;
public override bool CanWrite => true;
public override void Flush() { }
public override long Length => mLength;
public override long Position
{
get => mPosition;
set
{
if (!Ensure(value + 1))
throw new OutOfMemoryException($"Couldn't set {nameof(AWEMemoryStream)} to specified Position");
mPosition = value;
}
}
public override long Seek(long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Begin: Position = offset; return Position;
case SeekOrigin.Current: Position += offset; return Position;
case SeekOrigin.End: Position = Length + offset; return Position;
default: throw new InvalidOperationException();
}
}
bool Ensure(long len)
{
long blocksNeeded = (len + kBlockSize - 1) >> kBlockSizeBits;
while (mBlocks.Count < blocksNeeded)
{
var block = new AWEMemoryBlock();
if (!block.Allocate(kBlockSize))
return false;
mBlocks.Add(block);
}
return true;
}
public override void SetLength(long value)
{
if (!Ensure(value))
throw new OutOfMemoryException($"Couldn't set {nameof(AWEMemoryStream)} to specified Length");
mLength = value;
}
public override int Read(byte[] buffer, int offset, int count)
{
if (count + mPosition > mLength)
count = (int)(mLength - mPosition);
int ocount = count;
while (count > 0)
{
int todo = count;
long lblock = mPosition >> kBlockSizeBits;
if (lblock > int.MaxValue) throw new ArgumentOutOfRangeException();
int block = (int)lblock;
int blockOfs = (int)(mPosition - (block << kBlockSizeBits));
int remainsInBlock = kBlockSize - blockOfs;
if (remainsInBlock < todo)
todo = remainsInBlock;
if (mCurrBlock != block)
{
mCurrBlock = block;
if (!mBlocks[block].Map(mWindow))
throw new Exception($"Couldn't map required memory for {nameof(AWEMemoryStream)}.{nameof(Write)}");
}
Marshal.Copy(IntPtr.Add(mWindow, blockOfs), buffer, offset, todo);
count -= todo;
mPosition += todo;
offset += todo;
}
return ocount - count;
}
public override void Write(byte[] buffer, int offset, int count)
{
long end = mPosition + count;
if (!Ensure(end))
throw new OutOfMemoryException($"Couldn't reserve required resources for {nameof(AWEMemoryStream)}.{nameof(Write)}");
SetLength(end);
while (count > 0)
{
int todo = count;
long lblock = mPosition >> kBlockSizeBits;
if (lblock > int.MaxValue) throw new ArgumentOutOfRangeException();
int block = (int)lblock;
int blockOfs = (int)(mPosition - (block << kBlockSizeBits));
int remainsInBlock = kBlockSize - blockOfs;
if (remainsInBlock < todo)
todo = remainsInBlock;
if (mCurrBlock != block)
{
mCurrBlock = block;
if (!mBlocks[block].Map(mWindow))
throw new Exception($"Couldn't map required memory for {nameof(AWEMemoryStream)}.{nameof(Write)}");
}
Marshal.Copy(buffer, offset, IntPtr.Add(mWindow, blockOfs), todo);
count -= todo;
mPosition += todo;
offset += todo;
}
}
unsafe class AWEMemoryBlock : IDisposable
{
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AllocateUserPhysicalPages(IntPtr hProcess, ref uint NumberOfPages, IntPtr PageArray);
[DllImport("kernel32.dll")]
static extern bool MapUserPhysicalPages(IntPtr lpAddress, uint NumberOfPages, IntPtr UserPfnArray);
[DllImport("kernel32.dll")]
static extern bool FreeUserPhysicalPages(IntPtr hProcess, ref uint NumberOfPages, IntPtr UserPfnArray);
public enum ProcessorArchitecture
{
X86 = 0,
X64 = 9,
Arm = -1,
Itanium = 6,
Unknown = 0xFFFF,
}
[StructLayout(LayoutKind.Sequential)]
public struct SystemInfo
{
public ProcessorArchitecture ProcessorArchitecture; // WORD
public uint PageSize; // DWORD
public IntPtr MinimumApplicationAddress; // (long)void*
public IntPtr MaximumApplicationAddress; // (long)void*
public IntPtr ActiveProcessorMask; // DWORD*
public uint NumberOfProcessors; // DWORD (WTF)
public uint ProcessorType; // DWORD
public uint AllocationGranularity; // DWORD
public ushort ProcessorLevel; // WORD
public ushort ProcessorRevision; // WORD
}
[DllImport("kernel32", SetLastError = true)]
public static extern void GetSystemInfo(out SystemInfo lpSystemInfo);
[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
private uint lp;
private int hp;
public uint LowPart
{
get => lp;
set => lp = value;
}
public int HighPart
{
get => hp;
set => hp = value;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct LUID_AND_ATTRIBUTES
{
private LUID luid;
private uint attributes;
public LUID LUID
{
get => luid;
set => luid = value;
}
public uint Attributes
{
get => attributes;
set => attributes = value;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_PRIVILEGES
{
private uint prvct;
[MarshalAs(UnmanagedType.ByValArray)] //edited from stackoverflow article
private LUID_AND_ATTRIBUTES[] privileges;
public uint PrivilegeCount
{
get => prvct;
set => prvct = value;
}
public LUID_AND_ATTRIBUTES[] Privileges
{
get => privileges;
set => privileges = value;
}
}
[DllImport("advapi32", SetLastError = true)]
public static extern bool OpenProcessToken(IntPtr ProcessHandle, TokenAccessLevels DesiredAccess, out IntPtr TokenHandle);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, uint BufferLength, out TOKEN_PRIVILEGES PreviousState, out uint ReturnLength);
[Flags]
internal enum TokenAccessLevels
{
AssignPrimary = 0x00000001,
Duplicate = 0x00000002,
Impersonate = 0x00000004,
Query = 0x00000008,
QuerySource = 0x00000010,
AdjustPrivileges = 0x00000020,
AdjustGroups = 0x00000040,
AdjustDefault = 0x00000080,
AdjustSessionId = 0x00000100,
Read = 0x00020000 | Query,
Write = 0x00020000 | AdjustPrivileges | AdjustGroups | AdjustDefault,
AllAccess = 0x000F0000 |
AssignPrimary |
Duplicate |
Impersonate |
Query |
QuerySource |
AdjustPrivileges |
AdjustGroups |
AdjustDefault |
AdjustSessionId,
MaximumAllowed = 0x02000000
}
//http://stackoverflow.com/questions/13616330/c-sharp-adjusttokenprivileges-not-working-on-32bit
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid);
public static bool EnableDisablePrivilege(string PrivilegeName, bool EnableDisable)
{
var htok = IntPtr.Zero;
if (!OpenProcessToken(System.Diagnostics.Process.GetCurrentProcess().Handle, TokenAccessLevels.AdjustPrivileges | TokenAccessLevels.Query, out htok))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
return false;
}
var tkp = new TOKEN_PRIVILEGES { PrivilegeCount = 1, Privileges = new LUID_AND_ATTRIBUTES[1] };
if (!LookupPrivilegeValue(null, PrivilegeName, out var luid))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
return false;
}
tkp.Privileges[0].LUID = luid;
tkp.Privileges[0].Attributes = (uint)(EnableDisable ? 2 : 0);
TOKEN_PRIVILEGES prv;
uint rb;
if (!AdjustTokenPrivileges(htok, false, ref tkp, 256, out prv, out rb))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
return false;
}
return true;
}
static AWEMemoryBlock()
{
var si = new SystemInfo();
GetSystemInfo(out si);
PageSize = si.PageSize;
}
static uint PageSize;
static bool PrivilegeAcquired;
static object StaticLock = new object();
byte[] pageList;
static bool TryAcquirePrivilege()
{
lock (StaticLock)
{
if (PrivilegeAcquired)
{
return true;
}
if (EnableDisablePrivilege("SeLockMemoryPrivilege", true))
{
PrivilegeAcquired = true;
return true;
}
return false;
}
}
/// <exception cref="InvalidOperationException"><paramref name="byteSize"/> is equivalent to more than <see cref="UInt32.MaxValue">uint.MaxValue</see> pages</exception>
public bool Allocate(int byteSize)
{
if (!TryAcquirePrivilege())
return false;
long lnPagesRequested = byteSize / PageSize;
if (lnPagesRequested > uint.MaxValue)
throw new InvalidOperationException();
uint nPagesRequested = (uint)lnPagesRequested;
long sizePageList = IntPtr.Size * nPagesRequested;
pageList = new byte[sizePageList];
fixed (byte* pPageList = &pageList[0])
{
uint nPagesAllocated = nPagesRequested;
bool bResult = AllocateUserPhysicalPages(System.Diagnostics.Process.GetCurrentProcess().Handle, ref nPagesAllocated, new IntPtr(pPageList));
if (nPagesRequested != nPagesAllocated)
{
//abort! we're probably about to bomb the process, but just in case, we'll clean up
FreeUserPhysicalPages(System.Diagnostics.Process.GetCurrentProcess().Handle, ref nPagesAllocated, new IntPtr(pPageList));
pageList = null;
return false;
}
}
return true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public bool Map(IntPtr targetWindow)
{
// note: unmapping previous mapping seems unnecessary
if (pageList == null)
return false;
// map the desired physical pages
fixed (byte* pPageList = &pageList[0])
{
bool bResult = MapUserPhysicalPages(targetWindow, NumPages, new IntPtr(pPageList));
return bResult;
}
}
uint NumPages => (uint)(pageList.Length / (uint)IntPtr.Size);
protected virtual void Dispose(bool disposing)
{
if (pageList == null)
return;
fixed (byte* pPageList = &pageList[0])
{
uint nPagesRequested = NumPages;
FreeUserPhysicalPages(System.Diagnostics.Process.GetCurrentProcess().Handle, ref nPagesRequested, new IntPtr(pPageList));
pageList = null;
}
}
~AWEMemoryBlock()
{
Dispose(false);
}
}
}
}