i'm trying to get the C# equivalent of a C++ class, i've very very basic knowledge in C++ so idk if that's really possible or not. I've try something but i'm stuck. So if you can help me to "parse" this c++ class to c# and explain me how you do it or give some link who could help me. (Or give me a tips for using this c++ class into my c# project (idk if it's possible because of the managed/unmanaged code etc..)
C++ class:
class GameString
{
public:
GameString (GameString const&) = delete;
GameString& operator=(GameString const&) = delete;
GameString (const std::string &str)
: _buf (8)
{
append (str);
setHeader (1, length ());
}
GameString& operator+=(const std::string &str)
{
append (str);
setHeader (1, length ());
return *this;
}
std::size_t length ()
{
return _buf.size () - 8;
}
char *str ()
{
return reinterpret_cast<char*>(_buf.data () + 8);
}
private:
std::vector<unsigned char> _buf;
void append (const std::string &str)
{
for (auto &c : str)
{
_buf.push_back (c);
}
}
void setHeader (std::size_t ref, std::size_t len)
{
memcpy (&_buf[0], &ref, 4);
memcpy (&_buf[4], &len, 4);
}
};
C# class:
class GameString
{
private List<char> _buf = new List<char>(8);
public GameString(string str)
{
Append(str);
SetHeader(1, Length());
}
private void Append(string str)
{
foreach (char c in str)
{
_buf.Add(c);
}
}
public int Length()
{
return _buf.Count - 8;
}
public string Str()
{
// return new String(_buf.ToArray());
}
private void SetHeader(int rf, int length)
{
// memcpy(&_buf[0], &ref, 4);
// memcpy(&_buf[4], &len, 4);
}
}
And thanks for your help
public class GameString
{
private MemoryStream buf;
public GameString(string str)
{
buf = new MemoryStream();
// 8 empty bytes at the beginning
buf.SetLength(8);
buf.Position = 8;
Append(str);
}
// Different from C++ implementation. This one is public
// and updates the SetHeader
public void Append(string str)
{
byte[] utf8 = Encoding.UTF8.GetBytes(str);
buf.Write(utf8, 0, utf8.Length);
SetHeader(1, Length);
}
public static GameString operator +(GameString gs, string str)
{
gs.Append(str);
return gs;
}
// This one is a property instead of being a method
public int Length { get => (int)buf.Length - 8; }
// The char *str ()
public override string ToString()
{
return Encoding.UTF8.GetString(buf.GetBuffer(), 8, (int)buf.Length - 8);
}
// This one was missing in the C++ implementation. Returns the internal buffer.
// trimmed to the correct length. Note that it creates a copy!
public byte[] ToByteArray()
{
return buf.ToArray();
}
private void SetHeader(int #ref, int len)
{
// This could be optimized. Sadly the GetBytes create new
// arrays as the return value, instead of writing to a
// preexisting array.
byte[] temp = BitConverter.GetBytes(#ref);
Buffer.BlockCopy(temp, 0, buf.GetBuffer(), 0, temp.Length);
temp = BitConverter.GetBytes(len);
Buffer.BlockCopy(temp, 0, buf.GetBuffer(), 4, temp.Length);
}
}
And then:
var gs = new GameString("Foo");
gs.Append("Bar");
gs.Append("Baz");
gs += "Hello";
gs += "World";
string str = gs.ToString();
byte[] bytes = gs.ToByteArray();
I've made some changes to the C++ code, commented inside the C# code.
I'm using MemoryStream instead of a List<> or a StringBuilder. char in C# is 2 bytes, while in C it is 1 byte, so in C# you should use byte, not char.
Since the header is seemingly a fixed value of 1 and the length, unless i'm missing something
You could easily just use string and string.Length();
// instantiate
string gameString = "sadasd";
// get length
var len = gameString.Length();
// append
gameString += "sdfsfsdfdsf";
// get length again
var newLen = gameString.Length();
Related
i trying share a array via memoryfile c++ to c# based on this example:stream data from c++ to c# over shared memory.
work fine, but i just can get until position 3 from array, another position come 0.
C++ that creat MemoryFile
#include <windows.h>
#include <stdio.h>
struct Pair {
int length;
int data[10];
};
struct Pair* p;
HANDLE handle;
int dataSend[10]{ 500,33,44,66,2,55,98,7,52,36 };
bool startShare()
{
try
{
handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Pair), L"DataSend");
p = (struct Pair*) MapViewOfFile(handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(Pair));
return true;
}
catch (...)
{
return false;
}
}
int main()
{
if (startShare() == true)
{
printf("Memory Create");
while (true)
{
if (p != 0) {
for (int h = 0; h < 10; h++)
{
p->data[h] = dataSend[h];
printf("\n number %d", dataSend[h]);
}
}
else
puts("create shared memory error");
}
}
if (handle != NULL)
CloseHandle(handle);
return 0;
}
my C# Read
public static int[] data = new int[10];
public static MemoryMappedFile mmf;
public static MemoryMappedViewStream mmfvs;
static public bool MemOpen()
{
try
{
mmf = MemoryMappedFile.OpenExisting("DataSend");
mmfvs = mmf.CreateViewStream();
return true;
}
catch
{
return false;
}
}
public static void Main(string[] args)
{
while (true)
{
if (MemOpen())
{
byte[] blen = new byte[4];
mmfvs.Read(blen, 0, 4);
byte[] bPosition = new byte[280];
mmfvs.Read(bPosition, 0, 280);
Buffer.BlockCopy(bPosition, 0, data, 0, bPosition.Length);
for (int i = 0; i < data.Length; i++)
{
Console.WriteLine(data[i]);
}
}
}
}
work fine, but i just can get until position 3 from array, another position come 0.
Update, code work fine now
Just a detail,i return a array hex value example:52A7E600
but in my code c# get bit numbers like: 10300071984, how i cant convert in side c# to get same format?
to convert long value to hex in c# you could use:
long intValue = 10300071984;
// Convert long value 10300071984 -> 265EEA030 as a hex in a string variable
string hexValue = intValue.ToString("X");
I'm learning .Net core and find some interesting code where a function changing value in calling function without return type .Anyone please explain this concept.when i tried to change value of variable li in swap it doesn't reflected in ReverseWord function
static void Main(string[] args) {
char[] chars = "ABCDEFGH".ToCharArray();
ReverseWord(chars, 0, chars.Length - 1);
Console.WriteLine(new string(chars));
}
static void ReverseWord(char[] chars, int li, int hi) {
while (li++ < hi--)
{
Swap(chars, li, hi);
}
}
private static void Swap(char[] chars, int li, int hi) {
char temp = chars[li];
chars[li] = chars[hi];
chars[hi] = temp;
}
I am attempting to stream data from a c++ application to a C# application using shared memory. Based on example I found, I have:
c++ (sending)
struct Pair {
int length;
float data[3];
};
#include <windows.h>
#include <stdio.h>
struct Pair* p;
HANDLE handle;
float dataSend[3]{ 22,33,44 };
bool startShare()
{
try
{
handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Pair), L"DataSend");
p = (struct Pair*) MapViewOfFile(handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(Pair));
return true;
}
catch(...)
{
return false;
}
}
int main()
{
if (startShare() == true)
{
while (true)
{
if (p != 0) {
//dataSend[0] += 1; // here the value doesn't refresh
for (int h = 0; h < 3; h++)
{
p->data[h] = dataSend[h];
}
//dataSend[0] += 1; // here it does
}
else
puts("create shared memory error");
}
}
if (handle != NULL)
CloseHandle(handle);
return 0;
}
C# (receiving)
namespace sharedMemoryGET
{
class Program
{
public static float[] data = new float[3];
public static MemoryMappedFile mmf;
public static MemoryMappedViewStream mmfvs;
static public bool MemOpen()
{
try {
mmf = MemoryMappedFile.OpenExisting("DataSend");
mmfvs = mmf.CreateViewStream();
return true;
}
catch
{
return false;
}
}
public static void Main(string[] args)
{
while (true)
{
if (MemOpen())
{
byte[] blen = new byte[4];
mmfvs.Read(blen, 0, 4);
int len = blen[0] + blen[1] * 256 + blen[2] * 65536 + blen[2] * 16777216;
byte[] bPosition = new byte[12];
mmfvs.Read(bPosition, 0, 12);
Buffer.BlockCopy(bPosition, 0, data, 0, bPosition.Length);
Console.WriteLine(data[0]);
}
}
}
}
}
The c++ side never updates the variable, making me think i have missed something in my if-loop. Additionally, is a always-running loop the best way to go here? Is there a way to 'request' the data somehow from the C# side, to make this a more efficient system? Thank you.
..Actually this is working, I had the update for the variable in the wrong place. I have edited and will leave the code for others.
In the following bit of code, I am observing that the marshaler is reading past the 3 byte source array to populate another 8 bytes of data. With time, the code eventually throws a memory access violation. Is there a way to tell the marshaller to only marshal the first 3 bytes when converting a pointer to a structure? If I make the Articulations array "NonSerialized" then the constructor will throw an access violation when processing a source array of 11 bytes.
using System;
using System.Runtime.InteropServices;
namespace MarshallingTest
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Articulation
{
public const int BaseSize = 8;
public byte attribute1;
public byte attribute2;
public byte attribute3;
public byte attribute4;
public byte attribute5;
public byte attribute6;
public byte attribute7;
public byte attribute8;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class TestEntity
{
public const int BaseSize = 3;
public byte EntityId; // 1 byte
public byte Variable; // 1 byte
public byte NumArticulations; // 1 byte
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct)]
public Articulation[] Articulations; // 8 bytes each
public TestEntity(byte[] rawData)
{
unsafe
{
fixed (byte* pData = rawData)
{
// I am observing that the marshaler is reading past the 3 bytes
// to populate another 8 bytes of data. With time, the code
// will eventually throw a memory access violation.
//
// Is there a way to tell the marshaller to only marshal the
// first 3 bytes when converting a pointer to a structure?
Marshal.PtrToStructure((IntPtr) pData, this);
for (int i = 0; i < BaseSize + Articulation.BaseSize; i++)
{
Console.WriteLine("pData + " + i + " = " + *(pData + i));
}
}
}
}
public byte[] ToRaw()
{
byte[] byteArray = new byte[BaseSize + Articulation.BaseSize*Articulations.Length];
unsafe
{
fixed (byte* pData = byteArray)
{
Marshal.StructureToPtr(this, (IntPtr) pData, false);
}
}
return byteArray;
}
}
internal class Program
{
private const int TestDataSize = TestEntity.BaseSize;
private static void Main()
{
byte[] testData = new byte[TestDataSize];
for (int i = 0; i < TestDataSize; i++)
{
testData[i] = (byte) (i + 1);
}
TestEntity test = new TestEntity(testData);
// Print resulting array. You'll see that data outside the source
// byte array was marshalled into the test structure.
Console.WriteLine(test.EntityId);
Console.WriteLine(test.Variable);
Console.WriteLine(test.NumArticulations);
Console.WriteLine(test.Articulations[0].attribute1);
Console.WriteLine(test.Articulations[0].attribute2);
Console.WriteLine(test.Articulations[0].attribute3);
Console.WriteLine(test.Articulations[0].attribute4);
Console.WriteLine(test.Articulations[0].attribute5);
Console.WriteLine(test.Articulations[0].attribute6);
Console.WriteLine(test.Articulations[0].attribute7);
Console.WriteLine(test.Articulations[0].attribute8);
Console.WriteLine("Test complete.");
}
}
}
I have a System.Array of value struct types, something like this:
public value struct Position
{
int timestamp;
float x;
float y;
}
Position[] positions = new Position[1000 * 1000];
After I initialize the array with values, how can I get a byte[] of it's content, without serializing one item at a time?
In C++/CLI I would use a pin_ptr to get the pointer to the array content and I would copy the data from there. Can I do something like this in C#?
EDIT: I need to write the raw data to disk, as if it were a C struct, without any kind of serialization.
I tagged this question as C# for broader exposure, but actually I'm trying to serialize the data from IronPython, so this means I can't use any unsafe C# functionality.
Maybe this will help:
[Serializable()]
public struct Position
{
int timestamp;
float x;
float y;
}
static void Main(string[] args)
{
var positions = new Position[1000 * 1000];
GetBytes(positions);
}
private static byte[] GetBytes(object obj)
{
using (var memoryStream = new System.IO.MemoryStream())
{
var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
binaryFormatter.Serialize(memoryStream, obj);
return memoryStream.ToArray();
}
}
Here's a method that doesn't require unsafe code:
[Updated to remove the for loop and perform the copy in a single pass]
private static byte[] StructureToByteArray(Position[] posArray)
{
if (posArray == null || posArray.Length == 0)
{
return new byte[0];
}
var lenOfObject = Marshal.SizeOf(typeof(Position));
var len = lenOfObject * posArray.Length;
var arr = new byte[len];
var handle = GCHandle.Alloc(posArray, GCHandleType.Pinned);
try
{
var ptr = handle.AddrOfPinnedObject();
Marshal.Copy(ptr, arr, 0, len);
}
finally
{
handle.Free();
}
return arr;
}
I believe this is the equivalent to the C++/CLI pin_ptr using unsafe C# code:
public static unsafe byte[] GetBytes(Position[] positions)
{
byte[] result = new byte[positions.Length * Marshal.SizeOf(typeof(Position))];
fixed (Position* ptr = &positions[0])
{
Marshal.Copy((IntPtr)ptr, result, 0, result.Length);
}
return result;
}