I am using a Client Server architecture to download files from a centralized server. Due to the Limits of the Client machines I'm using Framework 3.5 on them and 4.6 on the Server.
On the Server I'm doing the following:
public IHttpActionResult MyControllerMedhod()
{
return MySecondMethod();
}
private HttpResponseMessage MySecondMethod()
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
FileStream stream = new FileStream("c:\temp\tester.dat", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "c:\temp\tester.dat";
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentLength = stream.Length;
return result;
}
On the Client machine I'm using:
webClient.DownloadFile("http://127.0.0.1/Download/MyControllerMethod", "c:\temp\test.dat");
It works quite fine BUT I have absolutely no control over how much bandwidth is used. For some of the Clients it would be of Advantage if less bandwidth is being used to download the files.
Now my question is: Is there any way to Limit the bandwidth that is being used per download? (either from Client side or Server side).
As remark: The Downloads can be data files as big as 800 or 900 MB.
One way that this can be achieved from the server side, if you don't have the ability to adjust IIS settings is to use a ThrottledStream. This is a class that I found somewhere way back when, if I can located the original source I'll be sure to link back to it.
Throttled Stream:
public class ThrottledStream : Stream
{
/// <summary>
/// A constant used to specify an infinite number of bytes that can be transferred per second.
/// </summary>
public const long Infinite = 0;
#region Private members
/// <summary>
/// The base stream.
/// </summary>
private Stream _baseStream;
/// <summary>
/// The maximum bytes per second that can be transferred through the base stream.
/// </summary>
private long _maximumBytesPerSecond;
/// <summary>
/// The number of bytes that has been transferred since the last throttle.
/// </summary>
private long _byteCount;
/// <summary>
/// The start time in milliseconds of the last throttle.
/// </summary>
private long _start;
#endregion
#region Properties
/// <summary>
/// Gets the current milliseconds.
/// </summary>
/// <value>The current milliseconds.</value>
protected long CurrentMilliseconds
{
get
{
return Environment.TickCount;
}
}
/// <summary>
/// Gets or sets the maximum bytes per second that can be transferred through the base stream.
/// </summary>
/// <value>The maximum bytes per second.</value>
public long MaximumBytesPerSecond
{
get
{
return _maximumBytesPerSecond;
}
set
{
if (MaximumBytesPerSecond != value)
{
_maximumBytesPerSecond = value;
Reset();
}
}
}
/// <summary>
/// Gets a value indicating whether the current stream supports reading.
/// </summary>
/// <returns>true if the stream supports reading; otherwise, false.</returns>
public override bool CanRead
{
get
{
return _baseStream.CanRead;
}
}
/// <summary>
/// Gets a value indicating whether the current stream supports seeking.
/// </summary>
/// <value></value>
/// <returns>true if the stream supports seeking; otherwise, false.</returns>
public override bool CanSeek
{
get
{
return _baseStream.CanSeek;
}
}
/// <summary>
/// Gets a value indicating whether the current stream supports writing.
/// </summary>
/// <value></value>
/// <returns>true if the stream supports writing; otherwise, false.</returns>
public override bool CanWrite
{
get
{
return _baseStream.CanWrite;
}
}
/// <summary>
/// Gets the length in bytes of the stream.
/// </summary>
/// <value></value>
/// <returns>A long value representing the length of the stream in bytes.</returns>
/// <exception cref="T:System.NotSupportedException">The base stream does not support seeking. </exception>
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
public override long Length
{
get
{
return _baseStream.Length;
}
}
/// <summary>
/// Gets or sets the position within the current stream.
/// </summary>
/// <value></value>
/// <returns>The current position within the stream.</returns>
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
/// <exception cref="T:System.NotSupportedException">The base stream does not support seeking. </exception>
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
public override long Position
{
get
{
return _baseStream.Position;
}
set
{
_baseStream.Position = value;
}
}
#endregion
#region Ctor
/// <summary>
/// Initializes a new instance of the <see cref="T:ThrottledStream"/> class with an
/// infinite amount of bytes that can be processed.
/// </summary>
/// <param name="baseStream">The base stream.</param>
public ThrottledStream(Stream baseStream)
: this(baseStream, ThrottledStream.Infinite)
{
// Nothing todo.
}
/// <summary>
/// Initializes a new instance of the <see cref="T:ThrottledStream"/> class.
/// </summary>
/// <param name="baseStream">The base stream.</param>
/// <param name="maximumBytesPerSecond">The maximum bytes per second that can be transferred through the base stream.</param>
/// <exception cref="ArgumentNullException">Thrown when <see cref="baseStream"/> is a null reference.</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <see cref="maximumBytesPerSecond"/> is a negative value.</exception>
public ThrottledStream(Stream baseStream, long maximumBytesPerSecond)
{
if (baseStream == null)
{
throw new ArgumentNullException("baseStream");
}
if (maximumBytesPerSecond < 0)
{
throw new ArgumentOutOfRangeException("maximumBytesPerSecond",
maximumBytesPerSecond, "The maximum number of bytes per second can't be negatie.");
}
_baseStream = baseStream;
_maximumBytesPerSecond = maximumBytesPerSecond;
_start = CurrentMilliseconds;
_byteCount = 0;
}
#endregion
#region Public methods
/// <summary>
/// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
/// </summary>
/// <exception cref="T:System.IO.IOException">An I/O error occurs.</exception>
public override void Flush()
{
_baseStream.Flush();
}
/// <summary>
/// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
/// </summary>
/// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source.</param>
/// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param>
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
/// <returns>
/// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.
/// </returns>
/// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </exception>
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
/// <exception cref="T:System.NotSupportedException">The base stream does not support reading. </exception>
/// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
public override int Read(byte[] buffer, int offset, int count)
{
Throttle(count);
return _baseStream.Read(buffer, offset, count);
}
/// <summary>
/// Sets the position within the current stream.
/// </summary>
/// <param name="offset">A byte offset relative to the origin parameter.</param>
/// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point used to obtain the new position.</param>
/// <returns>
/// The new position within the current stream.
/// </returns>
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
/// <exception cref="T:System.NotSupportedException">The base stream does not support seeking, such as if the stream is constructed from a pipe or console output. </exception>
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
public override long Seek(long offset, SeekOrigin origin)
{
return _baseStream.Seek(offset, origin);
}
/// <summary>
/// Sets the length of the current stream.
/// </summary>
/// <param name="value">The desired length of the current stream in bytes.</param>
/// <exception cref="T:System.NotSupportedException">The base stream does not support both writing and seeking, such as if the stream is constructed from a pipe or console output. </exception>
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
public override void SetLength(long value)
{
_baseStream.SetLength(value);
}
/// <summary>
/// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
/// </summary>
/// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</param>
/// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param>
/// <param name="count">The number of bytes to be written to the current stream.</param>
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
/// <exception cref="T:System.NotSupportedException">The base stream does not support writing. </exception>
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
/// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
/// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
public override void Write(byte[] buffer, int offset, int count)
{
Throttle(count);
_baseStream.Write(buffer, offset, count);
}
/// <summary>
/// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
/// </returns>
public override string ToString()
{
return _baseStream.ToString();
}
#endregion
#region Protected methods
/// <summary>
/// Throttles for the specified buffer size in bytes.
/// </summary>
/// <param name="bufferSizeInBytes">The buffer size in bytes.</param>
protected void Throttle(int bufferSizeInBytes)
{
// Make sure the buffer isn't empty.
if (_maximumBytesPerSecond <= 0 || bufferSizeInBytes <= 0)
{
return;
}
_byteCount += bufferSizeInBytes;
long elapsedMilliseconds = CurrentMilliseconds - _start;
if (elapsedMilliseconds > 0)
{
// Calculate the current bps.
long bps = _byteCount * 1000L / elapsedMilliseconds;
// If the bps are more then the maximum bps, try to throttle.
if (bps > _maximumBytesPerSecond)
{
// Calculate the time to sleep.
long wakeElapsed = _byteCount * 1000L / _maximumBytesPerSecond;
int toSleep = (int)(wakeElapsed - elapsedMilliseconds);
if (toSleep > 1)
{
try
{
// The time to sleep is more then a millisecond, so sleep.
Thread.Sleep(toSleep);
}
catch (ThreadAbortException)
{
// Eatup ThreadAbortException.
}
// A sleep has been done, reset.
Reset();
}
}
}
}
/// <summary>
/// Will reset the bytecount to 0 and reset the start time to the current time.
/// </summary>
protected void Reset()
{
long difference = CurrentMilliseconds - _start;
// Only reset counters when a known history is available of more then 1 second.
if (difference > 1000)
{
_byteCount = 0;
_start = CurrentMilliseconds;
}
}
#endregion
}
This is used by placing the original stream into the constructor along with the maximum bytes per second that you would like to throttle it to. For example:
public IHttpActionResult MyControllerMedhod()
{
return MySecondMethod();
}
private HttpResponseMessage MySecondMethod()
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
FileStream stream = new FileStream("c:\temp\tester.dat", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
result.Content = new ThrottledStream(stream, 153600);
result.Content.Headers.ContentDisposition = new
ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "c:\temp\tester.dat";
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentLength = stream.Length;
return result;
}
Edit:
Original Source: https://gist.github.com/passy/637319
Related
At the current moment I am trying to figure out a way to append a "1" bit to the front of a binary 32 bit integer, but only in front of the active bits. For example, "101" would turn into "1101", and 000 000 would turn into "1 000 000". Each binary integer would essentially be turned into triplets.
The reason I am wanting to do this is to implement a Hashed Octree with morton encoding. I am mainly attempting to follow this article here: https://geidav.wordpress.com/2014/08/18/advanced-octrees-2-node-representations/
In this article, it references adding a flag "1" bit to the front of morton code with its children in order to distinguish its location code from other location codes.
My Current Code is this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Collections;
using static Unity.Mathematics.math;
using Unity.Mathematics;
public struct Octree
{
NativeHashMap<int, OctreeNode> octreeNodes;
OctreeNode GetParentNode(OctreeNode node)
{
int locCodeParent = node.LocCode >> 3;
return LookupNode(locCodeParent);
}
OctreeNode LookupNode(int LocCode)
{
OctreeNode node;
if(!octreeNodes.TryGetValue(LocCode, out node))
{
Debug.Log("You done oofed dude, the octree node could not be found with the LocCode provided, please try again or stay oofed");
}
return node;
}
int GetNodeTreeDepth(OctreeNode node)
{
return (int)log2(node.LocCode)/3;
}
}
public struct OctreeNode
{
public int LocCode;
}
The LongFlags class below will maintain a (64-bit) set of ulong bit flags, as an abstraction. You can query the bits that are set, including querying the highest-set bit.
Your code does not show specifics; but you seem to want to be able to add a bit before another already set bit:
"101" would turn into "1101"
and also a not-set bit:
000 000 would turn into "1 000 000"
Perhaps you would keep track of an int value of your highest "Current" bit; and then use this class to set the next bit ... You can set and clear any individual bits.
For example, you could wrap the below LongFlags in a helper like this:
/// <summary>
/// Helper for bit flags, that tracks a <see cref="CurrentBit"/>.
/// The <see cref="BitLimit"/> is limited to sixty-four.
/// Bit positions are numbered from one to sixty-four,
/// right-to-left (lsb is one, msb is 64).
/// </summary>
[DataContract]
public class BitHelper
{
[DataMember]
private LongFlags longFlags = new LongFlags();
/// <summary>
/// Constructor.
/// </summary>
/// <param name="bitLimit">Required: sets <see cref="BitLimit"/>.</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public BitHelper(int bitLimit)
{
if ((bitLimit < 1)
|| (bitLimit > 64))
throw new ArgumentOutOfRangeException(nameof(bitLimit), bitLimit, #"[1, 64]");
BitLimit = bitLimit;
}
/// <summary>
/// Limits the highest bit that can be set. [1, 64].
/// (Bit positions are numbered from one to a maximum of sixty-four,
/// right-to-left (lsb is one, msb is 64).)
/// </summary>
[DataMember]
public int BitLimit { get; private set; }
/// <summary>
/// Identifies the current working bit position.
/// Defaults to one. Ranges: [1, BitLimit].
/// (Bit positions are numbered from one to a maximum of sixty-four,
/// right-to-left (lsb is one, msb is 64).)
/// </summary>
[DataMember]
public int CurrentBit { get; private set; } = 1;
/// <summary>
/// Returns the state of the <see cref="CurrentBit"/>.
/// </summary>
/// <returns>True if one, false if zero.</returns>
public bool IsCurrentBitSet
=> longFlags[CurrentBit];
/// <summary>
/// Increments the <see cref="CurrentBit"/>,
/// making no changes to bit values.
/// </summary>
/// <returns>This object for chaining.</returns>
/// <exception cref="InvalidOperationException">If the <see cref="CurrentBit"/>
/// is already at the <see cref="BitLimit"/>.</exception>
public BitHelper IncrementCurrentBit()
{
if (CurrentBit >= BitLimit)
throw new InvalidOperationException(BitLimit.ToString());
++CurrentBit;
return this;
}
/// <summary>
/// Sets the <see cref="CurrentBit"/> to one.
/// </summary>
/// <returns>This object for chaining.</returns>
public BitHelper SetCurrentBit()
{
longFlags.Set(CurrentBit);
return this;
}
/// <summary>
/// Sets the <see cref="CurrentBit"/> to zero.
/// </summary>
/// <returns>This object for chaining.</returns>
public BitHelper ClearCurrentBit()
{
longFlags.Clear(CurrentBit);
return this;
}
/// <summary>
/// Inverts the value of the <see cref="CurrentBit"/>.
/// </summary>
/// <returns>This object for chaining.</returns>
public BitHelper InvertCurrentBit()
{
longFlags[CurrentBit] = !longFlags[CurrentBit];
return this;
}
/// <summary>
/// Returns the position of the highest bit that is set:
/// [0, BitLimit]. Returns zero if no bits are set.
/// </summary>
public int HighestSetBit
=> longFlags.HighestFlag;
/// <summary>
/// Returns all 64 bits as a ULong.
/// </summary>
/// <returns>All 64 bits, unsigned.</returns>
public ulong ToULong()
=> longFlags.Flags;
/// <summary>
/// Returns all 64 bits as a Long.
/// </summary>
/// <returns>All 64 bits, signed.</returns>
public long ToLong()
=> (long)longFlags.Flags;
/// <summary>
/// Returns the lower 32 bits as a UInt
/// --- REGARDLESS of the setting of <see cref="BitLimit"/>.
/// </summary>
/// <returns>The lower 32 bits, unsigned.</returns>
public uint ToUInt()
=> (uint)longFlags.Flags;
/// <summary>
/// Returns the lower 32 bits as an Int
/// --- REGARDLESS of the setting of <see cref="BitLimit"/>.
/// </summary>
/// <returns>The lower 32 bits, signed.</returns>
public int ToInt()
=> (int)longFlags.Flags;
/// <summary>
/// Returns the lower 16 bits as a UShort
/// --- REGARDLESS of the setting of <see cref="BitLimit"/>.
/// </summary>
/// <returns>The lower 16 bits, unsigned.</returns>
public ushort ToUShort()
=> (ushort)longFlags.Flags;
/// <summary>
/// Returns the lower 16 bits as a short
/// --- REGARDLESS of the setting of <see cref="BitLimit"/>.
/// </summary>
/// <returns>The lower 16 bits, signed.</returns>
public short ToShort()
=> (short)longFlags.Flags;
/// <summary>
/// Returns the lower 8 bits as a Byte
/// --- REGARDLESS of the setting of <see cref="BitLimit"/>.
/// </summary>
/// <returns>The lower 8 bits, unsigned.</returns>
public byte ToByte()
=> (byte)longFlags.Flags;
/// <summary>
/// Returns the lower 8 bits as an SByte
/// --- REGARDLESS of the setting of <see cref="BitLimit"/>.
/// </summary>
/// <returns>The lower 8 bits, signed.</returns>
public sbyte ToSByte()
=> (sbyte)longFlags.Flags;
}
Here is LongFlags:
using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace Sc.Util.System
{
/// <summary>
/// A class holding <see langword="ulong"/> bit <see cref="Flags"/>.
/// Flags are numbered from one to sixty-four, from right-to-left in the
/// <see langword="ulong"/> value --- but the abstraction allows you to
/// ignore that as an implementation detail. This class implements
/// methods to set and clear flags, and set and clear flags from other
/// instances. This also implements implicit conversions to and from
/// <see langword="ulong"/> --- and therefore you may invoke methods with
/// <see langword="ulong"/> values. This is also
/// <see cref="IXmlSerializable"/> and <see cref="ICloneable"/>.
/// </summary>
[Serializable]
public sealed class LongFlags
: ICloneable,
IXmlSerializable
{
/// <summary>
/// Counts the bits that are set on the argument.
/// </summary>
/// <param name="flags">Arbitrary.</param>
/// <returns>A count of bits that are set.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int CountBits(ulong flags)
{
int result = 0;
for (int i = 0; i < 64; ++i) {
if ((flags & 1) == 1)
++result;
flags >>= 1;
}
return result;
}
/// <summary>
/// Returns the <see langword="ulong"/> VALUE of the SINGLE
/// highest bit that is set on the argument.
/// </summary>
/// <param name="flags">Arbitrary.</param>
/// <returns>The value of the single highest bit that is set.
/// Returns zero if no bits are set.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong GetHighestBitValue(ulong flags)
{
int highestBit = LongFlags.GetHighestBitPosition(flags);
return highestBit == 0
? 0UL
: 1UL << (highestBit - 1);
}
/// <summary>
/// Returns the <see langword="ulong"/> VALUE of the SINGLE
/// lowest bit that is set on the argument.
/// </summary>
/// <param name="flags">Arbitrary.</param>
/// <returns>The value of the single lowest bit that is set.
/// Returns zero if no bits are set.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong GetLowestBitValue(ulong flags)
{
int lowestBit = LongFlags.GetLowestBitPosition(flags);
return lowestBit == 0
? 0UL
: 1UL << (lowestBit - 1);
}
/// <summary>
/// Returns the position of highest bit that is set on the argument:
/// where the right-most bit is position one; and the left-most is sixty-four.
/// </summary>
/// <param name="flags">Arbitrary.</param>
/// <returns>The position of the highest bit that is set.
/// Returns zero if no bits are set.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetHighestBitPosition(ulong flags)
{
if (flags == 0UL)
return 0;
for (int i = 63; i >= 0; --i) {
if (((flags >> i) & 1) == 1)
return i + 1;
}
Debug.Fail($"Value is '{flags}' but iteration failed to find a set bit.");
return 0;
}
/// <summary>
/// Returns the position of lowest bit that is set on the argument:
/// where the right-most bit is position one; and the left-most is sixty-four.
/// </summary>
/// <param name="flags">Arbitrary.</param>
/// <returns>The position of the lowest bit that is set.
/// Returns zero if no bits are set.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetLowestBitPosition(ulong flags)
{
if (flags == 0UL)
return 0;
for (int i = 0; i < 64; ++i) {
if (((flags >> i) & 1) == 1)
return i + 1;
}
Debug.Fail($"Value is '{flags}' but iteration failed to find a set bit.");
return 0;
}
/// <summary>
/// Returns a new value from the <paramref name="flags"/>
/// with the <paramref name="predicate"/> removed.
/// </summary>
/// <param name="flags">Arbitrary.</param>
/// <param name="predicate">Arbitrary.</param>
/// <returns>Returns <paramref name="flags"/> <c>&</c> the
/// complement of the <paramref name="predicate"/>.</returns>
public static ulong Excluding(ulong flags, ulong predicate)
=> flags & ~predicate;
/// <summary>
/// Returns true if the <paramref name="source"/> has ANY of the bits that
/// are set on the <paramref name="flags"/>. Notice that if the
/// <paramref name="flags"/> are zero, this will return false.
/// </summary>
/// <param name="source">The source flags.
/// If zero, this will return false.</param>
/// <param name="flags">Arbitrary bits to search for.
/// If zero, this will return false.</param>
/// <returns>True if ANY <The name="flags"/> are present on the
/// <paramref name="source"/> (and at least one flags bit is set).</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool HasAnyBits(ulong source, ulong flags)
=> (source & flags) != 0UL;
/// <summary>
/// Returns true if the <paramref name="source"/> has ALL of the bits that
/// are set on the <paramref name="flags"/>. Notice that if the
/// <paramref name="flags"/> are zero, this will return false.
/// </summary>
/// <param name="source">The source flags.
/// If zero, this will return false.</param>
/// <param name="flags">Arbitrary bits to search for.
/// If zero, this will return false.</param>
/// <returns>True if ALL <The name="flags"/> are present on the
/// <paramref name="source"/> (and at least one flags bit is set).</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool HasAllBits(ulong source, ulong flags)
=> (flags != 0UL) && ((source & flags) == flags);
/// <summary>
/// Returns true if the <paramref name="source"/> has ONLY bits that are set
/// on the <paramref name="flags"/> --- false if any bit is set on the source
/// that is not defined on the flags. Notice that if the
/// <paramref name="flags"/> are zero, this will return false.
/// </summary>
/// <param name="source">The source flags.
/// If zero, this will return false.</param>
/// <param name="flags">Arbitrary bits to search for.
/// If zero, this will return false.</param>
/// <param name="requiresAll">If true, then <paramref name="source"/>
/// MUST contain ALL <paramref name="flags"/> AND NO other bits.
/// If false, the source may contain zero or more bits
/// present on the flags --- and no bits that are not present on the flags
/// (source need not contain all, but can only contain a bit on the flags).</param>
/// <returns>True if only the flags are present on the source --- false if any bit is
/// set on th source that is not defined on the flags.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool HasOnlyBits(ulong source, ulong flags, bool requiresAll)
=> (flags != 0UL)
&& (source != 0UL)
&& ((source & ~flags) == 0UL)
&& (!requiresAll
|| ((source & flags) == flags));
/// <summary>
/// Returns true if the <paramref name="source"/> has NONE of the
/// bits that are set on <paramref name="flags"/>. Notice that if the
/// <paramref name="flags"/> are zero, this will return TRUE.
/// </summary>
/// <param name="source">The source flags.
/// If zero, this will return true.</param>
/// <param name="flags">Arbitrary flags to search for.
/// If zero, this will return true.</param>
/// <returns>True if no flags bits are set here.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool HasNoBits(ulong source, ulong flags)
=> (source & flags) == 0UL;
/// <summary>
/// Checks the range.
/// </summary>
/// <param name="position">[1,64].</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void rangeCheckPosition(int position)
{
if ((position <= 0)
|| (position > 64))
throw new ArgumentOutOfRangeException(nameof(position), position, #"[1,64]");
}
/// <summary>
/// Default constructor creates an empty instance.
/// </summary>
public LongFlags() { }
/// <summary>
/// Creates a new instance with each flag position in the argument array set.
/// </summary>
/// <param name="flags">The flags to set.</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public LongFlags(params int[] flags)
=> Set(flags);
/// <summary>
/// Creates a new instance with the given bits set.
/// </summary>
/// <param name="flags">The bits to copy. This directly
/// sets <see cref="Flags"/>.</param>
public LongFlags(ulong flags)
=> Flags = flags;
/// <summary>
/// Creates a deep clone of the argument.
/// </summary>
/// <param name="clone">The value to copy.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private LongFlags(LongFlags clone)
=> Flags = clone.Flags;
XmlSchema IXmlSerializable.GetSchema()
=> null;
void IXmlSerializable.WriteXml(XmlWriter writer)
=> writer.WriteString(Flags.ToString(CultureInfo.InvariantCulture));
void IXmlSerializable.ReadXml(XmlReader reader)
{
if (reader.IsEmptyElement)
Flags = 0UL;
else {
reader.Read();
switch (reader.NodeType) {
case XmlNodeType.EndElement :
Flags = 0UL; // empty after all...
break;
case XmlNodeType.Text :
case XmlNodeType.CDATA :
Flags = ulong.Parse(reader.ReadContentAsString(), CultureInfo.InvariantCulture);
break;
default :
throw new InvalidOperationException("Expected text/cdata");
}
}
}
/// <summary>
/// The current bit flags. Flags are numbered from one to sixty-four: where
/// the right-most bit is one, and the left-most is sixty four.
/// Methods do not require knowledge of the flag positions; and flags
/// are simply numbered [1,64].
/// </summary>
public ulong Flags
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private set;
}
/// <summary>
/// An indexer that gets or sets a boolean indicating if the flag at the
/// given <paramref name="position"/> is set.
/// </summary>
/// <param name="position">[1,64].</param>
/// <returns>True if the flag is set.</returns>
public bool this[int position]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => IsSet(position);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set {
if (value)
Set(position);
else
Clear(position);
}
}
/// <summary>
/// Returns true if the flag at the given position is set.
/// </summary>
/// <param name="position">The position to test: [1,64].</param>
/// <returns>True if the flag is set.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsSet(int position)
{
LongFlags.rangeCheckPosition(position);
return LongFlags.HasAnyBits(Flags, 1UL << (position - 1));
}
/// <summary>
/// Returns true if each flag in the argument array is set.
/// This will return FALSE if none are provided.
/// </summary>
/// <param name="positions">[1,64].</param>
/// <returns>True if all provided flags are set. NOTICE: this will
/// return FALSE if none are provided.</returns>
public bool IsAllSet(params int[] positions)
{
if (positions.Length == 0)
return false;
foreach (int position in positions) {
if (!IsSet(position))
return false;
}
return true;
}
/// <summary>
/// Returns true if ANY flag in the argument array is set.
/// This will return FALSE if none are provided.
/// </summary>
/// <param name="positions">[1,64].</param>
/// <returns>True if ANY provided flag is set; AND if AT LEAST ONE
/// is provided.</returns>
public bool IsAnySet(params int[] positions)
{
foreach (int position in positions) {
if (IsSet(position))
return true;
}
return false;
}
/// <summary>
/// Returns true if all flags are set.
/// </summary>
public bool IsFull
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Flags == ulong.MaxValue;
}
/// <summary>
/// Returns true if no flags are set.
/// </summary>
public bool IsEmpty
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Flags == 0UL;
}
/// <summary>
/// Counts the flags that are set.
/// </summary>
/// <returns>A count of <see cref="Flags"/> bits that are set.</returns>
public int Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => LongFlags.CountBits(Flags);
}
/// <summary>
/// Returns the position of highest flag that is set.
/// </summary>
/// <returns>The position of the highest bit that is set on <see cref="Flags"/>.</returns>
public int HighestFlag
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => LongFlags.GetHighestBitPosition(Flags);
}
/// <summary>
/// Returns the position of lowest flag that is set.
/// </summary>
/// <returns>The position of the lowest bit that is set on <see cref="Flags"/>.</returns>
public int LowestFlag
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => LongFlags.GetLowestBitPosition(Flags);
}
/// <summary>
/// Returns the <see langword="ulong"/> VALUE of the SINGLE
/// highest bit that is set.
/// </summary>
/// <returns>The value of the single highest bit that is set on <see cref="Flags"/>.</returns>
public ulong HighestFlagValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => LongFlags.GetHighestBitValue(Flags);
}
/// <summary>
/// Returns the <see langword="ulong"/> VALUE of the SINGLE
/// lowest bit that is set.
/// </summary>
/// <returns>The value of the single lowest bit that is set on <see cref="Flags"/>.</returns>
public ulong LowestFlagValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => LongFlags.GetLowestBitValue(Flags);
}
/// <summary>
/// Sets the flag at the position specified by the argument.
/// </summary>
/// <param name="position">[1,64].</param>
/// <returns>This object for chaining.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LongFlags Set(int position)
{
LongFlags.rangeCheckPosition(position);
Flags |= 1UL << (position - 1);
return this;
}
/// <summary>
/// Sets the flag at each specified position.
/// </summary>
/// <param name="positions">[1,64].</param>
/// <returns>This object for chaining.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LongFlags Set(params int[] positions)
{
ulong flags = Flags;
try {
foreach (int position in positions) {
Set(position);
}
return this;
} catch {
Flags = flags;
throw;
}
}
/// <summary>
/// Sets all flags to one.
/// </summary>
/// <returns>This object for chaining.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LongFlags SetAll()
{
Flags = ulong.MaxValue;
return this;
}
/// <summary>
/// Clears the flag at the position specified by the argument.
/// </summary>
/// <param name="position">[1,64].</param>
/// <returns>This object for chaining.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LongFlags Clear(int position)
{
LongFlags.rangeCheckPosition(position);
Flags &= ~(1UL << (position - 1));
return this;
}
/// <summary>
/// Clears the flag at each position specified in the argument array.
/// </summary>
/// <param name="positions">[1,64].</param>
/// <returns>This object for chaining.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LongFlags Clear(params int[] positions)
{
ulong flags = Flags;
try {
foreach (int position in positions) {
Clear(position);
}
return this;
} catch {
Flags = flags;
throw;
}
}
/// <summary>
/// Resets all <see cref="Flags"/> to zero.
/// </summary>
/// <returns>This object for chaining.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LongFlags Clear()
{
Flags = 0UL;
return this;
}
/// <summary>
/// Sets <see cref="Flags"/> to the argument's value.
/// </summary>
/// <param name="clone">The value to copy.</param>
/// <returns>This object for chaining.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LongFlags SetFrom(LongFlags clone)
{
Flags = clone.Flags;
return this;
}
/// <summary>
/// Sets <see cref="Flags"/> to the argument's value.
/// </summary>
/// <param name="clone">The value to copy.</param>
/// <returns>This object for chaining.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LongFlags SetFrom(ulong clone)
{
Flags = clone;
return this;
}
/// <summary>
/// Adds all of the flags in the argument to this instance.
/// </summary>
/// <param name="flags">Arbitrary flags to add.</param>
/// <returns>This object for chaining.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LongFlags AddAllFlags(LongFlags flags)
{
Flags |= flags.Flags;
return this;
}
/// <summary>
/// Removes all flags defined on the argument from this instance.
/// </summary>
/// <param name="flags">Arbitrary flags to remove.</param>
/// <returns>This object for chaining.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LongFlags RemoveAllFlags(LongFlags flags)
{
Flags &= ~flags.Flags;
return this;
}
/// <summary>
/// Returns true if this instance has ANY of the <see cref="Flags"/>
/// defined on the argument. Notice that if the
/// <paramref name="flags"/> are zero, this will return false.
/// </summary>
/// <param name="flags">Arbitrary flags to search for.</param>
/// <returns>True if any flags are present here
/// (and at least one flag bit is set).</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasAny(LongFlags flags)
=> LongFlags.HasAnyBits(Flags, flags.Flags);
/// <summary>
/// Returns true if this instance has ALL of the <see cref="Flags"/>
/// defined on the argument. Notice that if the
/// <paramref name="flags"/> are zero, this will return false.
/// </summary>
/// <param name="flags">Arbitrary flags to search for.</param>
/// <returns>True if ALL flags are present here
/// (and at least one flag bit is set).</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasAll(LongFlags flags)
=> LongFlags.HasAllBits(Flags, flags.Flags);
/// <summary>
/// Returns true if this instance has ONLY flags that are set
/// on the <paramref name="flags"/> --- false if any flag is set here
/// that is not defined on the flags. Notice that if the
/// <paramref name="flags"/> are zero, this will return false
/// --- and if this <see cref="Flags"/> is zero this returns false.
/// </summary>
/// <param name="flags">Arbitrary flags to search for.
/// If zero, this will return false.</param>
/// <param name="requiresAll">If true, then this
/// MUST contain ALL <paramref name="flags"/> AND NO other flags.
/// If false, this may contain zero or more flags
/// present on the flags --- and no flags that are not present on the flags
/// (this need not contain all, but can only contain a flag on the flags).</param>
/// <returns>True if only the flags are present here --- false if any flag is
/// set here that is not defined on the flags.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasOnly(LongFlags flags, bool requiresAll)
=> LongFlags.HasOnlyBits(Flags, flags.Flags, requiresAll);
/// <summary>
/// Returns true if this instance has NONE of the <see cref="Flags"/>
/// defined on the argument.
/// </summary>
/// <param name="flags">Arbitrary.</param>
/// <returns>True if no flags are present here.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasNone(LongFlags flags)
=> LongFlags.HasNoBits(Flags, flags.Flags);
/// <summary>
/// Returns a deep clone of this object.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LongFlags Clone()
=> new LongFlags(this);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
object ICloneable.Clone()
=> Clone();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ulong(LongFlags longFlags)
=> longFlags.Flags;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator LongFlags(ulong flags)
=> new LongFlags(flags);
public override string ToString()
=> $"{nameof(LongFlags)}"
+ "["
+ $"{Convert.ToString((byte)(Flags >> 56), 2)}"
+ $" {Convert.ToString((byte)(Flags >> 48), 2)}"
+ $" {Convert.ToString((byte)(Flags >> 40), 2)}"
+ $" {Convert.ToString((byte)(Flags >> 32), 2)}"
+ $" {Convert.ToString((byte)(Flags >> 24), 2)}"
+ $" {Convert.ToString((byte)(Flags >> 16), 2)}"
+ $" {Convert.ToString((byte)(Flags >> 8), 2)}"
+ $" {Convert.ToString((byte)Flags, 2)}"
+ "]";
}
}
I have a class which contains multiple functions to read and write memory. But it's missing the readByte function and writeByte function.
I've tried to create those in the following format:
public byte readByte(IntPtr address)
{
byte[] buffer = new byte[1];
ReadMemory(address, buffer, 1);
//return BitConverter.ToUInt32(buffer, 0);
}
But couldn't think of a BitConverter return type. Does anyone have a idea how I could create those functions? Since the returned value is only a byte as you can see in this screenshot:
Some functions from the class:
/// <summary>
/// Reads 32 bit signed integer at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <returns></returns>
public int ReadInt32(IntPtr address)
{
byte[] buffer = new byte[4];
ReadMemory(address, buffer, 4);
return BitConverter.ToInt32(buffer, 0);
}
/// <summary>
/// Reads 32 bit unsigned integer at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <returns></returns>
public uint ReadUInt32(IntPtr address)
{
byte[] buffer = new byte[4];
ReadMemory(address, buffer, 4);
return BitConverter.ToUInt32(buffer, 0);
}
/// <summary>
/// Reads single precision value at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <returns></returns>
public float ReadFloat(IntPtr address)
{
byte[] buffer = new byte[4];
ReadMemory(address, buffer, 4);
return BitConverter.ToSingle(buffer, 0);
}
/// <summary>
/// Reads double precision value at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <returns></returns>
public double ReadDouble(IntPtr address)
{
byte[] buffer = new byte[8];
ReadMemory(address, buffer, 8);
return BitConverter.ToDouble(buffer, 0);
}
/// <summary>
/// Writes 32 bit unsigned integer at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <param name="value">Value</param>
/// <returns></returns>
public void WriteUInt32(IntPtr address, uint value)
{
byte[] buffer = BitConverter.GetBytes(value);
WriteMemory(address, buffer, 4);
}
/// <summary>
/// Writes 32 bit signed integer at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <param name="value">Value</param>
/// <returns></returns>
public void WriteInt32(IntPtr address, int value)
{
byte[] buffer = BitConverter.GetBytes(value);
WriteMemory(address, buffer, 4);
}
/// <summary>
/// Writes single precision value at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <param name="value">Value</param>
/// <returns></returns>
public void WriteFloat(IntPtr address, float value)
{
byte[] buffer = BitConverter.GetBytes(value);
WriteMemory(address, buffer, 4);
}
/// <summary>
/// Writes double precision value at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <param name="value">Value</param>
/// <returns></returns>
public void WriteDouble(IntPtr address, double value)
{
byte[] buffer = BitConverter.GetBytes(value);
WriteMemory(address, buffer, 8);
}
Because currently I'm calling the class in the following way:
public void updatePlayerStatistic(int prestigeLevel)
{
Process[] processes = Process.GetProcessesByName("iw7_ship");
if (processes.Length > 0)
{
using (CheatEngine.Memory memory = new CheatEngine.Memory(processes[0]))
{
// Prestige code
IntPtr prestigeAddress = memory.GetAddress("iw7_ship.exe", (IntPtr)0x04105320, new int[] { 0x6E5 });
//memory.WriteUInt32(prestigeAddress, uint.Parse(prestigeLevel.ToString()));
MessageBox.Show(memory.ReadUInt32(prestigeAddress).ToString());
}
}
}
Which would always return 0. As you can see in the following screenshot:
But clearly the value is 8 which is shown in CheatEngine.
Whole class:
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace InfiniteTrainer.CheatEngine
{
/// <summary>
/// Represents an access to a remote process memory
/// </summary>
public class Memory : IDisposable
{
private Process process;
private IntPtr processHandle;
private bool isDisposed;
public const string OffsetPattern = "(\\+|\\-){0,1}(0x){0,1}[a-fA-F0-9]{1,}";
/// <summary>
/// Initializes a new instance of the Memory
/// </summary>
/// <param name="process">Remote process</param>
public Memory(Process process)
{
if (process == null)
throw new ArgumentNullException("process");
this.process = process;
processHandle = Win32.OpenProcess(
Win32.ProcessAccessType.PROCESS_VM_READ | Win32.ProcessAccessType.PROCESS_VM_WRITE |
Win32.ProcessAccessType.PROCESS_VM_OPERATION, true, (uint)process.Id);
if (processHandle == IntPtr.Zero)
throw new InvalidOperationException("Could not open the process");
}
#region IDisposable
~Memory()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (isDisposed)
return;
Win32.CloseHandle(processHandle);
process = null;
processHandle = IntPtr.Zero;
isDisposed = true;
}
#endregion
#region Properties
/// <summary>
/// Gets the process to which this memory is attached to
/// </summary>
public Process Process
{
get
{
return process;
}
}
#endregion
/// <summary>
/// Finds module with the given name
/// </summary>
/// <param name="name">Module name</param>
/// <returns></returns>
protected ProcessModule FindModule(string name)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
foreach (ProcessModule module in process.Modules)
{
if (module.ModuleName.ToLower() == name.ToLower())
return module;
}
return null;
}
/// <summary>
/// Gets module based address
/// </summary>
/// <param name="moduleName">Module name</param>
/// <param name="baseAddress">Base address</param>
/// <param name="offsets">Collection of offsets</param>
/// <returns></returns>
public IntPtr GetAddress(string moduleName, IntPtr baseAddress, int[] offsets)
{
if (string.IsNullOrEmpty(moduleName))
throw new ArgumentNullException("moduleName");
ProcessModule module = FindModule(moduleName);
if (module == null)
return IntPtr.Zero;
else
{
//int address = module.BaseAddress.ToInt32() + baseAddress.ToInt32();
long address = module.BaseAddress.ToInt64() + baseAddress.ToInt64();
return GetAddress((IntPtr)address, offsets);
}
}
/// <summary>
/// Gets address
/// </summary>
/// <param name="baseAddress">Base address</param>
/// <param name="offsets">Collection of offsets</param>
/// <returns></returns>
public IntPtr GetAddress(IntPtr baseAddress, int[] offsets)
{
if (baseAddress == IntPtr.Zero)
throw new ArgumentException("Invalid base address");
//int address = baseAddress.ToInt32();
long address = baseAddress.ToInt64();
if (offsets != null && offsets.Length > 0)
{
byte[] buffer = new byte[4];
foreach (int offset in offsets)
address = ReadInt32((IntPtr)address) + offset;
}
return (IntPtr)address;
}
/// <summary>
/// Gets address pointer
/// </summary>
/// <param name="address">Address</param>
/// <returns></returns>
public IntPtr GetAddress(string address)
{
if (string.IsNullOrEmpty(address))
throw new ArgumentNullException("address");
string moduleName = null;
int index = address.IndexOf('"');
if (index != -1)
{
// Module name at the beginning
int endIndex = address.IndexOf('"', index + 1);
if (endIndex == -1)
throw new ArgumentException("Invalid module name. Could not find matching \"");
moduleName = address.Substring(index + 1, endIndex - 1);
address = address.Substring(endIndex + 1);
}
int[] offsets = GetAddressOffsets(address);
int[] _offsets = null;
IntPtr baseAddress = offsets != null && offsets.Length > 0 ?
(IntPtr)offsets[0] : IntPtr.Zero;
if (offsets != null && offsets.Length > 1)
{
_offsets = new int[offsets.Length - 1];
for (int i = 0; i < offsets.Length - 1; i++)
_offsets[i] = offsets[i + 1];
}
if (moduleName != null)
return GetAddress(moduleName, baseAddress, _offsets);
else
return GetAddress(baseAddress, _offsets);
}
/// <summary>
/// Gets address offsets
/// </summary>
/// <param name="address">Address</param>
/// <returns></returns>
protected static int[] GetAddressOffsets(string address)
{
if (string.IsNullOrEmpty(address))
return new int[0];
else
{
MatchCollection matches = Regex.Matches(address, OffsetPattern);
int[] offsets = new int[matches.Count];
string value;
char ch;
for (int i = 0; i < matches.Count; i++)
{
ch = matches[i].Value[0];
if (ch == '+' || ch == '-')
value = matches[i].Value.Substring(1);
else
value = matches[i].Value;
offsets[i] = Convert.ToInt32(value, 16);
if (ch == '-')
offsets[i] = -offsets[i];
}
return offsets;
}
}
/// <summary>
/// Reads memory at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <param name="buffer">Buffer</param>
/// <param name="size">Size in bytes</param>
public void ReadMemory(IntPtr address, byte[] buffer, int size)
{
if (isDisposed)
throw new ObjectDisposedException("Memory");
if (buffer == null)
throw new ArgumentNullException("buffer");
if (size <= 0)
throw new ArgumentException("Size must be greater than zero");
if (address == IntPtr.Zero)
throw new ArgumentException("Invalid address");
uint read = 0;
if (!Win32.ReadProcessMemory(processHandle, address, buffer, (uint)size, ref read) ||
read != size)
throw new AccessViolationException();
}
/// <summary>
/// Writes memory at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <param name="buffer">Buffer</param>
/// <param name="size">Size in bytes</param>
public void WriteMemory(IntPtr address, byte[] buffer, int size)
{
if (isDisposed)
throw new ObjectDisposedException("Memory");
if (buffer == null)
throw new ArgumentNullException("buffer");
if (size <= 0)
throw new ArgumentException("Size must be greater than zero");
if (address == IntPtr.Zero)
throw new ArgumentException("Invalid address");
uint write = 0;
if (!Win32.WriteProcessMemory(processHandle, address, buffer, (uint)size, ref write) ||
write != size)
throw new AccessViolationException();
}
/// <summary>
/// Reads 32 bit signed integer at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <returns></returns>
public int ReadInt32(IntPtr address)
{
byte[] buffer = new byte[4];
ReadMemory(address, buffer, 4);
return BitConverter.ToInt32(buffer, 0);
}
/// <summary>
/// Reads 32 bit unsigned integer at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <returns></returns>
public uint ReadUInt32(IntPtr address)
{
byte[] buffer = new byte[4];
ReadMemory(address, buffer, 4);
return BitConverter.ToUInt32(buffer, 0);
}
/// <summary>
/// Reads single precision value at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <returns></returns>
public float ReadFloat(IntPtr address)
{
byte[] buffer = new byte[4];
ReadMemory(address, buffer, 4);
return BitConverter.ToSingle(buffer, 0);
}
/// <summary>
/// Reads double precision value at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <returns></returns>
public double ReadDouble(IntPtr address)
{
byte[] buffer = new byte[8];
ReadMemory(address, buffer, 8);
return BitConverter.ToDouble(buffer, 0);
}
/// <summary>
/// Writes 32 bit unsigned integer at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <param name="value">Value</param>
/// <returns></returns>
public void WriteUInt32(IntPtr address, uint value)
{
byte[] buffer = BitConverter.GetBytes(value);
WriteMemory(address, buffer, 4);
}
/// <summary>
/// Writes 32 bit signed integer at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <param name="value">Value</param>
/// <returns></returns>
public void WriteInt32(IntPtr address, int value)
{
byte[] buffer = BitConverter.GetBytes(value);
WriteMemory(address, buffer, 4);
}
/// <summary>
/// Writes single precision value at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <param name="value">Value</param>
/// <returns></returns>
public void WriteFloat(IntPtr address, float value)
{
byte[] buffer = BitConverter.GetBytes(value);
WriteMemory(address, buffer, 4);
}
/// <summary>
/// Writes double precision value at the address
/// </summary>
/// <param name="address">Memory address</param>
/// <param name="value">Value</param>
/// <returns></returns>
public void WriteDouble(IntPtr address, double value)
{
byte[] buffer = BitConverter.GetBytes(value);
WriteMemory(address, buffer, 8);
}
}
}
If you carefully read the code you've written, you'd see that no conversion is necessary, hence your difficulty finding this (unnecessary) BitConverter function.
Simply return the only byte you've read:
public byte readByte(IntPtr address)
{
byte[] buffer = new byte[1];
ReadMemory(address, buffer, 1);
return buffer[0];
}
You don't need a BitConverter. You already have a byte, which you can return:
public byte readByte(IntPtr address)
{
byte[] buffer = new byte[1];
ReadMemory(address, buffer, 1);
return buffer[0];
}
Some background information: BitConverter is there to convert raw binary data (represented as byte[]) to specific types. It exists that you don't have to worry about the internal structure of the respective types (especially endianness can be a bummer). That howewer is completely unnecessary for a byte, since you already have the byte in your array.
I need to send very large zip files via http. The files are too large to write to the file system or memory.I would like to zip on the fly and send back via http output stream. I'm using a custom web server that will only take a stream as a response, I don't have access to the http response output stream. (response.Send(stream)).
My idea is to create a helper/proxy stream that can be passed into the response.Send method. (See ZipCreateStream below)
Basically this encapsulates a memory stream, the files to be zipped and the archive. The response.Send method will buffer copy the stream passed in calling stream.Read, the ZipCreateStream implements a Read method that will zip a buffered chunk into it's memory stream (the archive) then copy that to the buffer passed in by response.Send.
This works great until I try to truncate the memory stream in ZipCreateStream Read method. What I'm trying to do there is keep the memory usage low, after the bytes in the temporary stream are copied I want to "clear" the memory stream.
When I do this the zip file ends up corrupted.
Any help/thoughts would be much appreciated! I'm truly stumped on this one.
Note: I'm using SharpZipLib for zipping.
public class ZipCreateStream : Stream
{
readonly string[] entries;
readonly string[] files;
ZipOutputStream archive;
ZipEntry archiveEntry;
int fileNumber;
Stream fileStream;
volatile MemoryStream stream;
bool hasDisposed;
int streamOffset;
readonly bool truncate;
public ZipCreateStream(string[] files, string[] entries, int compressionLevel = 0, bool truncate = false)
{
this.files = files;
this.entries = entries;
if (files.Length != entries.Length)
{
throw new ArgumentException("Files and entries mismatch");
}
this.truncate = truncate;
stream = new MemoryStream();
archive = new ZipOutputStream(stream);
archive.SetLevel(compressionLevel);
}
public override bool CanRead
{
get
{
return true;
}
}
/// <summary>
/// When overridden in a derived class, gets a value indicating whether the current stream supports seeking.
/// </summary>
/// <returns>
/// true if the stream supports seeking; otherwise, false.
/// </returns>
public override bool CanSeek
{
get
{
return false;
}
}
/// <summary>
/// When overridden in a derived class, gets a value indicating whether the current stream supports writing.
/// </summary>
/// <returns>
/// true if the stream supports writing; otherwise, false.
/// </returns>
public override bool CanWrite
{
get
{
return false;
}
}
/// <summary>
/// When overridden in a derived class, gets the length in bytes of the stream.
/// </summary>
/// <returns>
/// A long value representing the length of the stream in bytes.
/// </returns>
/// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking. </exception>
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
public override long Length
{
get
{
throw new NotSupportedException();
}
}
/// <summary>
/// When overridden in a derived class, gets or sets the position within the current stream.
/// </summary>
/// <returns>
/// The current position within the stream.
/// </returns>
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
/// <exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception>
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
public override long Position { get; set; }
protected override void Dispose(bool disposing)
{
archive.Dispose();
stream.Dispose();
if (fileStream != null)
{
fileStream.Dispose();
}
base.Dispose(disposing);
}
/// <summary>
/// When overridden in a derived class, clears all buffers for this stream and causes any buffered data to be written
/// to the underlying device.
/// </summary>
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
public override void Flush()
{
if (stream == null)
{
return;
}
stream.Flush();
}
/// <summary>
/// When overridden in a derived class, sets the position within the current stream.
/// </summary>
/// <returns>
/// The new position within the current stream.
/// </returns>
/// <param name="offset">A byte offset relative to the <paramref name="origin" /> parameter. </param>
/// <param name="origin">
/// A value of type <see cref="T:System.IO.SeekOrigin" /> indicating the reference point used to
/// obtain the new position.
/// </param>
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
/// <exception cref="T:System.NotSupportedException">
/// The stream does not support seeking, such as if the stream is
/// constructed from a pipe or console output.
/// </exception>
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
public override long Seek(long offset, SeekOrigin origin)
{
return stream.Seek(offset, origin);
}
/// <summary>
/// When overridden in a derived class, sets the length of the current stream.
/// </summary>
/// <param name="value">The desired length of the current stream in bytes. </param>
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
/// <exception cref="T:System.NotSupportedException">
/// The stream does not support both writing and seeking, such as if the
/// stream is constructed from a pipe or console output.
/// </exception>
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
public override void SetLength(long value)
{
stream.SetLength(value);
}
/// <summary>
/// When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position
/// within the stream by the number of bytes read.
/// </summary>
/// <returns>
/// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many
/// bytes are not currently available, or zero (0) if the end of the stream has been reached.
/// </returns>
/// <param name="buffer">
/// An array of bytes. When this method returns, the buffer contains the specified byte array with the
/// values between <paramref name="offset" /> and (<paramref name="offset" /> + <paramref name="count" /> - 1) replaced
/// by the bytes read from the current source.
/// </param>
/// <param name="offset">
/// The zero-based byte offset in <paramref name="buffer" /> at which to begin storing the data read
/// from the current stream.
/// </param>
/// <param name="count">The maximum number of bytes to be read from the current stream. </param>
/// <exception cref="T:System.ArgumentException">
/// The sum of <paramref name="offset" /> and <paramref name="count" /> is
/// larger than the buffer length.
/// </exception>
/// <exception cref="T:System.ArgumentNullException"><paramref name="buffer" /> is null. </exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">
/// <paramref name="offset" /> or <paramref name="count" /> is
/// negative.
/// </exception>
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
/// <exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
public override int Read(byte[] buffer, int offset, int count)
{
// Get the next set of buffered data from internal buffer
if (offset != 0)
{
throw new ArgumentException("Not seekable");
}
if (streamOffset == stream.Length)
{
// when all buffered data is copied, clear the memory stream
if (truncate)
{
streamOffset = 0;
stream.SetLength(0);
}
if (fileStream != null && fileStream.Position == fileStream.Length)
{
fileNumber++;
fileStream.Dispose();
fileStream = null;
}
if (fileNumber < files.Length)
{
if (fileStream == null)
{
string file = files[fileNumber];
string entry = entries[fileNumber];
fileStream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
archiveEntry = new ZipEntry(ZipEntry.CleanName(entry));
archive.PutNextEntry(archiveEntry);
}
byte[] writebuffer = new byte[buffer.Length];
while (stream.Length - streamOffset < buffer.Length)
{
int bytesRead = fileStream.Read(writebuffer, 0, writebuffer.Length);
if (bytesRead > 0)
{
archive.Write(writebuffer, 0, bytesRead);
}
else
{
archive.Flush();
break;
}
}
}
}
if (streamOffset == stream.Length && !hasDisposed)
{
hasDisposed = true;
archive.Finish();
}
stream.Seek(streamOffset, SeekOrigin.Begin);
int readCount = stream.Read(buffer, 0, count);
streamOffset += readCount;
return readCount;
}
/// <summary>
/// When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current
/// position within this stream by the number of bytes written.
/// </summary>
/// <param name="buffer">
/// An array of bytes. This method copies <paramref name="count" /> bytes from
/// <paramref name="buffer" /> to the current stream.
/// </param>
/// <param name="offset">
/// The zero-based byte offset in <paramref name="buffer" /> at which to begin copying bytes to the
/// current stream.
/// </param>
/// <param name="count">The number of bytes to be written to the current stream. </param>
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
}
The problem is in Position property.
Below you can find 2 working classes for this task. They use standard .NET ZipArchive class:
public class ThroughZipStream : Stream
{
private readonly ThroughMemoryStream _ms = new ThroughMemoryStream();
private readonly ZipArchive _zip;
private readonly Stream _entryStream;
private readonly Stream _input;
private byte[] _buffer = new byte[10000]; // buffer to read from input stream
public ThroughZipStream(Stream input, string entryName)
{
_input = input;
_zip = new ZipArchive(_ms, ZipArchiveMode.Create, true);
var entry = _zip.CreateEntry(entryName);
_entryStream = entry.Open();
}
public override int Read(byte[] buffer, int offset, int count)
{
while (_ms.Length < count && _buffer != null)
{
var len = _input.Read(_buffer, 0, _buffer.Length);
if (len == 0)
{
_entryStream.Dispose();
_zip.Dispose();
_buffer = null;
break;
}
_entryStream.Write(_buffer, 0, len);
}
return _ms.Read(buffer, offset, count);
}
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return false; } } // we can't seek
public override bool CanWrite { get { return false; } }
public override void Flush() { }
public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } }
public override long Length { get { throw new NotImplementedException(); } }
public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); }
public override void SetLength(long value) { throw new NotImplementedException(); }
public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); }
}
public class ThroughMemoryStream : MemoryStream
{
private long _position;
public override bool CanSeek { get { return false; } }
public override void Write(byte[] buffer, int offset, int count)
{
base.Write(buffer, offset, count);
_position += count;
}
public override int Read(byte[] buffer, int offset, int count)
{
var msBuffer = GetBuffer();
var realCount = Math.Min(Length, count);
Array.Copy(msBuffer, 0, buffer, 0, realCount);
Array.Copy(msBuffer, realCount, msBuffer, 0, Length - realCount);
SetLength(Length - realCount);
return (int)realCount;
}
public override long Position
{
get { return _position; }
set { throw new NotImplementedException(); }
}
}
Usage:
var compressedStream = new ThroughZipStream(fileStream, "somefile.txt")
PS: I had the same problem and couldn't google any solution. It was a big surprise for me, I think this way is the best one to pipeline a stream.
I'm working on .NET C# app that implements virtual files drag and drop from app to Windows Explorer. I got implementation idea and sample code from here. After file drop the app downloads a file and writes it to IStream wrapper. That works fine on Windows 7 x64, but that works very slow for files about 30 MB and larger and takes a lot of CPU resources and Memory on Windows 8.1.
Any ideas will be appreciated. Thanks in advance. The code is:
1) IStreamWrapper class
private class IStreamWrapper : Stream
{
/// <summary>
/// IStream instance being wrapped.
/// </summary>
private IStream _iStream;
/// <summary>
/// Initializes a new instance of the IStreamWrapper class.
/// </summary>
/// <param name="iStream">IStream instance to wrap.</param>
public IStreamWrapper(IStream iStream)
{
_iStream = iStream;
}
/// <summary>
/// Gets a value indicating whether the current stream supports reading.
/// </summary>
public override bool CanRead
{
get { return false; }
}
/// <summary>
/// Gets a value indicating whether the current stream supports seeking.
/// </summary>
public override bool CanSeek
{
get { return false; }
}
/// <summary>
/// Gets a value indicating whether the current stream supports writing.
/// </summary>
public override bool CanWrite
{
get { return true; }
}
/// <summary>
/// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
/// </summary>
public override void Flush()
{
throw new NotImplementedException();
}
/// <summary>
/// Gets the length in bytes of the stream.
/// </summary>
public override long Length
{
get { throw new NotImplementedException(); }
}
/// <summary>
/// Gets or sets the position within the current stream.
/// </summary>
public override long Position
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
/// <summary>
/// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
/// </summary>
/// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source.</param>
/// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param>
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
/// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
/// <summary>
/// Sets the position within the current stream.
/// </summary>
/// <param name="offset">A byte offset relative to the origin parameter.</param>
/// <param name="origin">A value of type SeekOrigin indicating the reference point used to obtain the new position.</param>
/// <returns>The new position within the current stream.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
/// <summary>
/// Sets the length of the current stream.
/// </summary>
/// <param name="value">The desired length of the current stream in bytes.</param>
public override void SetLength(long value)
{
throw new NotImplementedException();
}
/// <summary>
/// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
/// </summary>
/// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</param>
/// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param>
/// <param name="count">The number of bytes to be written to the current stream.</param>
public override void Write(byte[] buffer, int offset, int count)
{
if (offset == 0)
{
// Optimize common case to avoid creating extra buffers
_iStream.Write(buffer, count, IntPtr.Zero);
}
else
{
// Easy way to provide the relevant byte[]
_iStream.Write(buffer.Skip(offset).ToArray(), count, IntPtr.Zero);
}
}
}
2) Creating IStream and writing to it:
public void SetData(short dataFormat, int index, Action<Stream> streamData)
{
...
var iStream = NativeMethods.CreateStreamOnHGlobal(IntPtr.Zero, true);
if (streamData != null)
{
// Wrap in a .NET-friendly Stream and call provided code to fill it
using(var stream = new IStreamWrapper(iStream))
{
streamData(stream); // calls downloadFile(stream);
}
}
Marshal.ReleaseComObject(iStream);
...
}
// that will be called by streamData(stream)
private void downloadFile(Stream wStream) {
...
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode != HttpStatusCode.OK)
{
throw new WebException(String.Format("Server error (HTTP {0}: {1}).", response.StatusCode, response.StatusDescription));
}
using (Stream stream = response.GetResponseStream())
{
byte[] buffer = new byte[4096];
while ((bytesRead = stream.Read(buffer, 0, 4096)) != 0)
{
wStream.Write(buffer, 0, bytesRead);
}
}
...
}
I was digging through some code, when suddenly a wild bug appeared...
Ok let's start.
I created this code to represent a position in a script while parsing.
/// <summary>
/// Represents a position in script. (Used for error reporting)
/// </summary>
public sealed class Position
{
/// <summary>
/// Line count.
/// </summary>
public int Line { get; set; }
/// <summary>
/// Character count.
/// </summary>
public int Char { get; set; }
/// <summary>
/// Index data.
/// </summary>
public int Index { get; set; }
/// <summary>
/// Initialize new Position object to standard values.
/// </summary>
public Position()
{
this.Line = 1;
this.Char = 1;
this.Index = 0;
}
/// <summary>
/// Copy a Position object.
/// </summary>
/// <param name="pos"></param>
public Position(Position pos)
{
this.Line = pos.Line;
this.Char = pos.Char;
this.Index = pos.Index;
}
/// <summary>
/// Initialize new Position object to given parameters.
/// </summary>
/// <param name="p_index">The index in stream.</param>
/// <param name="p_line">The line count.</param>
/// <param name="p_char">The character count</param>
public Position(int p_index, int p_line, int p_char)
{
this.Line = p_line;
this.Char = p_char;
this.Index = p_index;
}
/// <summary>
/// Check if 2 Position objects are equal.
/// </summary>
/// <param name="p1">Left operand.</param>
/// <param name="p2">Right operand.</param>
/// <returns>Returns true, if both position objects are equal.</returns>
public static Boolean operator ==(Position p1, Position p2)
{
return
p1.Index == p2.Index &&
p1.Char == p2.Char &&
p1.Line == p2.Line;
}
/// <summary>
/// Check if 2 Position objects are not equal.
/// </summary>
/// <param name="p1">Left operand.</param>
/// <param name="p2">Right operand.</param>
/// <returns></returns>
public static Boolean operator !=(Position p1, Position p2)
{
return !(p1 == p2);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
/// <summary>
/// Equals overload.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj is Position)
return this == (Position)obj;
return false;
}
/// <summary>
/// ToString override.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return String.Format("{0} - {1} - {2}", this.Index, this.Line, this.Char);
}
}
But... When I do something like this:
var pos1 = new Position();
var pos2 = pos1;
pos2.Char = 10;
Then I change the value of pos1.Char too... I don't know this behavior from C#. The other classes behave the same.
The copy constructor did not help.
I use .NET 4.5 and VS 2012 Update 3...
Can someone tell me what causes this behavior? Or atleast how to get arround this behavior...
pos1 is a reference to the new object. By setting pos2 to pos1, you now have two references to the same object. If you want two different objects, you should do
var pos1 = new Position(); // Create a new object
var pos2 = new Position(pos1); // Use your copy constructor
pos2.Char = 10;
Your ´Position´ class is a ´reference type´
When you equal pos2 to pos1 it points to the same memory location.
Changing the property of one object will thus change the other one also as it is the same object
This isn't a bug; this is correct C# behavior. Position is a class, which is a reference type. The assignment var pos2 = pos1; doesn't copy anything, it just creates another reference to the same Position instance.
You want to call your copy constructor like this:
var pos2 = new Position(pos1);