How to copy float* to IntPtr? - c#

Short description of my task:
As parameter of my function I got some buffer (IntPtr).
I need to extract some information from this buffer and copy information to audioFrame.AudioBuffer buffer (IntPtr).
Problem:
Needed information placed in channelData[c] (float*), I need to copy this information to destStart (IntPtr).
Code:
private void SomeFunc(IntPtr buffer)
{
...
AudioFrame audioFrame; // audioFrame.AudioBuffer is IntPtr
...
unsafe
{
float** channelData = (float**)buffer.ToPointer();
for (int c = 0; c < 2; c++)
{
IntPtr destStart = new IntPtr(audioFrame.AudioBuffer.ToInt64() + (c * audioFrame.ChannelStride));
Marshal.Copy(channelData[c], 0, destStart, audioFrame.NumSamples); ///< problem in this line, channelData[c] is float*
}
}
...
}
Edit
Little more context: I got this buffer from CEF (https://github.com/cefsharp/CefSharp). In fact this function work as callback. When I got new audio data I need to send this data throught NDI (https://www.ndi.tv/)
AudioFrame is wrapper over the NDI structure
public struct audio_frame_v2_t
{
// The sample-rate of this buffer
public int sample_rate;
// The number of audio channels
public int no_channels;
// The number of audio samples per channel
public int no_samples;
// The timecode of this frame in 100ns intervals
public Int64 timecode;
// The audio data
public IntPtr p_data;
// The inter channel stride of the audio channels, in bytes
public int channel_stride_in_bytes;
// Per frame metadata for this frame. This is a NULL terminated UTF8 string that should be
// in XML format. If you do not want any metadata then you may specify NULL here.
public IntPtr p_metadata;
// This is only valid when receiving a frame and is specified as a 100ns time that was the exact
// moment that the frame was submitted by the sending side and is generated by the SDK. If this
// value is NDIlib_recv_timestamp_undefined then this value is not available and is NDIlib_recv_timestamp_undefined.
public Int64 timestamp;
}

Perhaps consider spans here:
var fromSpan = new Span<float>(channelData[c], audioFrame.NumSamples);
var toSpan = new Span<float>(destStart.ToPointer(), audioFrame.NumSamples);
fromSpan.CopyTo(toSpan);
Or Buffer.MemoryCopy:
var size = sizeof(float) * audioFrame.NumSamples;
Buffer.MemoryCopy(channelData[c], destStart.ToPointer(), size, size);
(note that in both cases it would be better to include knowledge of the actual buffer sizes if you have it, to avoid buffer overflow scenarios; I've just assumed the sizes are valid, for simplicity; there's also Unsafe.CopyBlock which works a lot like Buffer.MemoryCopy)

Related

System.AccessViolationException: shared_ptr between C# .NET and C++ applications

In our project we communicate two applications, one in C# and the other in C++, via named pipes. Our intention is to pass memory pointers between them and be able to access the objects pointed by them in either application. Our current code rises a System.AccessViolationException:
System.AccessViolationException:
Attempted to read or write protected memory. This is often an
indication that other memory is corrupt.
So far we are using a shared_ptr that points to a custom struct and writting the pointer to the buffer in C++ as seen below:
typedef struct {
int one;
int a;
int two;
int b;
} DATA_STRUCT; // C++ struct
DATA_STRUCT ds;
ds.one = 10;
ds.a = 5;
ds.two = 99;
ds.b = 0;
shared_ptr<DATA_STRUCT> ptr_ds(new DATA_STRUCT);
shared_ptr<DATA_STRUCT> p(ptr_ds);
*ptr_ds = ds;
const int size = BUFFER_SIZE;
char buf[size];
memset(buf, 0xCC, 100);
while (keepReading)
{
printf("Write message:");
scanf("%s", buf);
memcpy(buf, &p, sizeof(shared_ptr<DATA_STRUCT>));
if (strcmp(buf, "quit") == 0)
keepReading = false;
else
{
WriteFile(hPipe1, buf, dwBytesToWrite, &cbWritten, NULL);
memset(buf, 0xCC, 100);
}
}
Then, in C# we read the whole buffer, we keep the bytes with the relevant information in another buffer (Rc) and convert the byte array to our custom data structure using unsafe IntPtr as you can see below:
buffer = new byte[BUFFER_SIZE];
bytesRead = clientCSharp.stream.Read(buffer, 0, BUFFER_SIZE);
public struct DATA_STRUCT
{
public int one;
public int a;
public int two;
public int b;
}; // C# struct
unsafe
{
Buffer.BlockCopy(buffer, 0, Rc, 0, ReadLength);
DATA_STRUCT ds = new DATA_STRUCT();
IntPtr aux_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
IntPtr final_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
Marshal.Copy(Rc, 0, aux_ptr, 4);
final_ptr = (IntPtr)Marshal.PtrToStructure(aux_ptr, typeof(IntPtr));
ds = (DATA_STRUCT)Marshal.PtrToStructure(final_ptr, typeof(IntPtr));
}
The exception rises when we try to access the final_ptr in order to load the DATA_STRUCT, the last code line presented above. Here I give some Debug images:
C++ Debug image with Pointer value written to the named pipe buffer
C# Debug image with Pointer value read from the named pipe reduced buffer (Rc)
Could it be something related to the pointer length? As it seems to me in the C++ application it has 8bytes and in the C# application it has 16bytes? Dhould we declare a safe memory location for C# and C++? If yes, then how could it be done?
Note: Our goal is to work with the unsafe IntPtr in the C# application. In this example we are loading the DATA_STRUCT object because we wanted to be sure that in the C# application we are retrieving the same object passed in the C++ application. The final applications is meant to be used in Windows.
Application data spaces are completely distinct, and have been for many years. you can't simply pass a raw pointer between applications and expect to access the same memory.
The normal approach is to serialise the content of your object, squirt it through your pipe and then reconstruct the object at the receiver.
You can set up named shared memory regions, and these are faster to share large objects (in unix, and I assume in windows), but these shared regions will probably not be located at the same address, so still only good for raw data.

Converting Delphi pointer and stream.Read to c#

I'm trying to convert an old Delphi app into C#. It does some stuff with binary files written via packed records which I've put below. However, only the BInfoRec record is guaranteed to be in the file and appearing first. The others may or may not be in there, and the order of them is unknown. I'm having trouble with one method in particular. It's getting the number of bytes being read in via FileStream.Read and reading those into one of the packed records. Then, in the first if statement (in the delphi version), it is allocating memory on the heap, and doing the same thing as before, but reading it into a pointer. I'm trying to figure out the best way to go about this but I'm by no means an expert with Delphi.
Delphi code:
StartP = packed record
x:SmallInt;
y:SmallInt;
end;
InfoP = packed record
Ycoord:double;
Xcoord:double;
//other vars here
end;
HeadP = packed record
NumP:DWORD;
SizeStruct:DWORD;
SizePoStruct:DWORD;
//other vars here
end;
BInfoRec = packed record
StructNum : WORD ;
in_size : WORD ;
//other variables here
end;
var
tStream:TFileStream;
bInfo:BInfoRec;
RestOfBFile:Pointer;
sizeofRest:Integer;
Function LoadBFile(FileName:String):Boolean;
var
sizeread:Integer;
begin
Try
LoadBFile:=False;
tStream:=TFileStream.Create(Filename,fmOpenRead );
sizeofRest:=tStream.Size-Sizeof(bInfo);
sizeread:=tStream.Read(bInfo,Sizeof(bInfo));
if sizeread = Sizeof(bInfo) then
begin //best way to convert this?
RestOfBFile:=AllocMem(sizeofRest);
sizeread:=tStream.Read(RestOfBFile^,sizeofRest);
if SizeofRest= SizeRead then
LoadBFile:=True;
end;
tStream.Free;
except
LoadBFile:=False;
tStream.Free;
end;
end;
C# (what I have so far):
[Serializable()]
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct StartP
{
public short x;
public short y;
}
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct InfoP
{
public double Ycoord;
public double Xcoord;
//other vars here
}
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct HeadP
{
public UInt32 NumP;
public UInt32 SizeStruct;
public UInt32 SizePoStruct;
//other vars here
}
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct BInfoRec
{
public ushort StructNum;
public ushort in_size;
}
BInfoRec bInfo;
int sizeOfRest;
private Boolean LoadBFile(string fileName)
{
int sizeRead;
byte[] buffer = new byte[Marshal.SizeOf(bInfo)];
try
{
using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None))
{
sizeOfRest = (int)stream.Length - Marshal.SizeOf(typeof(BInfoRec));
sizeRead = stream.Read(buffer, 0, Marshal.SizeOf(typeof(BInfoRec)));
if (sizeRead == Marshal.SizeOf(typeof(BInfoRec)))
{
//what goes here??
if (sizeOfRest == sizeRead)
{
return true;
}
}
}
}
catch (Exception ex)
{
return false;
}
}
I was thinking about creating a new byte array of unknown size and using a BinaryReader to read in the rest of the file to that array, then just checking the size of that. Not sure if it's the best way though?
It's a block of memory of arbitrary size. I don't see that you have many options other than a byte array. Yes you could allocate unmanaged memory (e.g. with Marshal.AllocHGlobal) but that would hardly be convenient.
So, yes, if I were you I would allocate a byte array, and read the contents into it.

How to read string from a C structure when no field is available?

There's a C structure which is written to the socket on the other side. I am reading in C#. The structure is like follows:
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
struct StupidStruct
{
// fid sequence
public short fid_seq;
// field value length, after the length, follow the field content
public ushort length;
}
After reading this from socket, I need to read the string that I receive. The layer I do this does not have access to the buffer itself. It only has access to the structure. How to do this?
EDIT :
The function where I need to do this:
public void Handle(ref StupidStruct s)
{
//GCHandle handle = GCHandle.Alloc(s.length, GCHandleType.Pinned);
//var ptr = handle.AddrOfPinnedObject();
//ptr = IntPtr.Add(ptr, sizeof (ushort));
//The above is my initial attempt. But I think the address I get here is not the buffer address. What to do?
handle.Free();
}
So are you reading it in c or C#? Which one is listening on the socket? If C# is, skip the interop and read the bytes off the wire directly. Otherwise you need to do some research, because you will need an intptr to the start of the char array to do anything. Structs are value types, so getting the address if the struct is pointless as it is on the stack anyway.

Make this Readprocessmemory code a lot more efficient

Introduction
Currently I am using someone's class to read bytes in memory (via pointers). The code I have so far works perfectly, I don't really want to change the way the class is setup if possible (because it works), but hopefully some minor tweaks can be made to the class and my code to make it highly efficient.
What I achieve at the moment:
Start off with a pointer address in memory, reads a byte at that address, adds the data to an array, adds 1 to the original address so we can now read the next address (eg original address is 24004, once the byte is stored, increment 1 and next address to read becomes 24005).
Reads the byte at the next address (24005), adds this to the same array, adds 1 to that address (next to read becomes 24006).
And so forth for a fixed number of iterations (approximately 10,000).
The problem:
Making 10,000 calls to readprocessmemory one after the other causes a system delay of 20 seconds whilst it goes about its business.
What I hope can be achieved:
Perform Readprocessmemory once only, specifying 10,000 bytes of data to be read (instead of just a byte at a time for 10,000 iterations), save this to the array in the same format as I had before with individual bytes (I am aware therefore that instead of array {0} (1) (2).. etc.. I will now just have array {0}, so I would imagine I would need an efficient means of splitting this very large number out into 10,000 numbers (in another array)) The data stored at each address are integers. So for 5 addresses: array {12345} becomes {1}{2}{3}{4}{5}. Where 1 2 3 4 or 5 could just as well be 1 200 40 43 or 20, for example.
So ideally, if I could wave my newbie wand, it would look something like this (class below as well as what I have so far):
Iteration code:
private void label1_Click(object sender, EventArgs e)
{
int[] valuesSeperated[200];
List<byte> PreArray = new List<byte>();
Process[] test = Process.GetProcessesByName("MyProcess"); //Get process handle
int baseAddress = test[0].MainModule.BaseAddress.ToInt32(); //Get base address
byte ReadX = MyClass.ReadPointerByte("MyProcess", BaseAddress, new int[] { 0xc, 0x0, 0x2 }); //call memory reading function (including memory offsets)
PreArray.Add(ReadX);
byte[] PreArrayToInt = PreArray.ToArray();
int[] MYConvertedBytes = PreArray ToInt.Select(x => (int)x).ToArray();
foreach (int i in MYConvertedBytes)
{
valuesSeperated // (don't really know what to do here, if the read was successful I would have a long number at [0], so now need to separate these as if I had read each one in memory one at a time.
}
//new array with 10,000 values created.
}
Class:
[DllImport("kernel32", EntryPoint = "ReadProcessMemory")]
private static extern byte ReadProcessMemoryByte(int Handle, int Address, ref byte Value, int Size, ref int BytesRead);
public static byte ReadPointerByte(string EXENAME, int Pointer, int[] Offset)
{
byte Value = 0;
checked
{
try
{
Process[] Proc = Process.GetProcessesByName(EXENAME);
if (Proc.Length != 0)
{
int Bytes = 0;
int Handle = OpenProcess(PROCESS_ALL_ACCESS, 0, Proc[0].Id);
if (Handle != 0)
{
foreach (int i in Offset)
{
ReadProcessMemoryInteger((int)Handle, Pointer, ref Pointer, 4, ref Bytes);
Pointer += i;
}
ReadProcessMemoryByte((int)Handle, Pointer, ref Value, 2, ref Bytes);
CloseHandle(Handle);
}
}
}
catch
{ }
}
return Value;
}
Some advices:
Do not call OpenProcess / CloseHandle inside your "managed wrapper" (ReadPointerByte, or whatever...), you can use the Process.Handle property.
To avoid possible errors related with page's permissions, you might need to wrap calls to ReadProcessMemory with VirtualProtectEx (one to 'unprotect', allowing reads, and another to 'restore' the previous protection).
Some code:
// from http://www.pinvoke.net/default.aspx/kernel32.readprocessmemory
[DllImport("kernel32", EntryPoint = "ReadProcessMemory")]
private static extern bool ReadProcessMemory(IntPtr Handle, IntPtr Address,
[Out] byte[] Arr, int Size, out int BytesRead);
public static byte[] ReadBytes(IntPtr hnd, IntPtr Pointer, int Length)
{
byte[] Arr = new byte[Length];
int Bytes = 0;
if(!ReadProcessMemory(hnd, Pointer, Arr, Length, out Bytes)){
// Throw exception ...
}
// Check if Bytes == Length ...
return Arr;
}
private void button1_Click(object sender, EventArgs e)
{
//Get process handle
Process[] test = Process.GetProcessesByName("notepad++");
//Get base address
IntPtr baseAddress = test[0].MainModule.BaseAddress;
int bytesToRead = 16;
int[] valuesSeparated = new int[bytesToRead / 4];
byte[] ret = ReadBytes(test[0].Handle, baseAddress, bytesToRead);
// Interpret ret as you like ...
// Convert ret to int[]
valuesSeparated = ....
}
[The iteration process]
You have two options here:
Get a full snapshot of the target process's memory into a byte[], and perform your algorithm in this array
You can exec a readprocessmemory for each iteration. I believe this is your best option.
Regardless of targe-process-memory-reading-technique, your algorithm is this (I'm having a real hard time translating your text into an implementation...):
Input: BaseAddress of process, Offsets
Output: byte[] Ret
Steps:
1: LastPtr = BaseAddress
2: IdxOffset = 0
3: Offset = Offsets[IdxOffset]
4: LastValue = Memory[LastPtr + Offset]
5: Ret.Add(LastValue)
6: IdxOffset++
7: LastPtr = LastValue // Is this it?????
8: If IdxOffset < Offsets.Length then return else goto 3

C# FMOD Playing stream in realtime

i am trying to play a stream in real time ( I keep appedning data to it as it comes in from a nexternal source) but no matter what FMOD doesn't want to carry on playing after the first chunk that got loaded, it seems as it is copying the memory stream/decoding it before playing, then as it is playing it doesn't use my stream anymore.
I am using the following to play my stream:
var exinfo = new FMOD.CREATESOUNDEXINFO();
exinfo.cbsize = Marshal.SizeOf(exinfo);
exinfo.length = (uint)_buffer.Length;
_result = System.createStream(_buffer, MODE.CREATESTREAM | MODE.OPENMEMORY_POINT , ref exinfo, ref _sound);
FMODErrorCheck(_result);
_result = System.playSound(FMOD.CHANNELINDEX.FREE, _sound, false, ref _channel);
FMODErrorCheck(_result);
But no matter what, it only plays the amount of data that is in the stream at the point of calling playSound.
Can anyone know how to modify the buffer in real time? After the stream has started playing...?
I would recommend you check out the "usercreatedsound" example that ships with FMOD, it should do what you require.
The basic idea is you define the properties of the sound you wish to play in the CreateSoundExInfo structure and provide it with callbacks which you can use to load / stream data from wherever you like.
Function pointer:
private FMOD.SOUND_PCMREADCALLBACK pcmreadcallback = new FMOD.SOUND_PCMREADCALLBACK(PCMREADCALLBACK);
Callback used to populate the FMOD sound:
private static FMOD.RESULT PCMREADCALLBACK(IntPtr soundraw, IntPtr data, uint datalen)
{
unsafe
{
short *stereo16bitbuffer = (short *)data.ToPointer();
// Populate the 'stereo16bitbuffer' with sound data
}
return FMOD_OK;
}
Code to create the sound that will use the callback:
// ...Usual FMOD initialization code here...
FMOD.CREATESOUNDEXINFO exinfo = new FMOD.CREATESOUNDEXINFO();
// You define your required frequency and channels
exinfo.cbsize = Marshal.SizeOf(exinfo);
exinfo.length = frequency * channels * 2 * 5; // *2 for sizeof(short) *5 for 5 seconds
exinfo.numchannels = (int)channels;
exinfo.defaultfrequency = (int)frequency;
exinfo.format = FMOD.SOUND_FORMAT.PCM16;
exinfo.pcmreadcallback = pcmreadcallback;
result = system.createStream((string)null, (FMOD.MODE.DEFAULT | FMOD.MODE.OPENUSER | FMOD.MODE.LOOP_NORMAL), ref exinfo, ref sound);
That should be sufficient to get you going, hope this helps.
If you wish to stream raw data, not PCM data you could achieve this by overriding the FMOD file system. There are two ways to achieve this, the first is by setting the file callbacks in the CreateSoundExInfo structure if this is for one specific file. The second is you can set the file system globally for all FMOD file operations (incase you want to do this with multiple files).
I will explain the latter, it would be trivial to switch to the former though. Refer to the "filecallbacks" FMOD example for a complete example.
Function pointers:
private FMOD.FILE_OPENCALLBACK myopen = new FMOD.FILE_OPENCALLBACK(OPENCALLBACK);
private FMOD.FILE_CLOSECALLBACK myclose = new FMOD.FILE_CLOSECALLBACK(CLOSECALLBACK);
private FMOD.FILE_READCALLBACK myread = new FMOD.FILE_READCALLBACK(READCALLBACK);
private FMOD.FILE_SEEKCALLBACK myseek = new FMOD.FILE_SEEKCALLBACK(SEEKCALLBACK);
Callbacks:
private static FMOD.RESULT OPENCALLBACK([MarshalAs(UnmanagedType.LPWStr)]string name, int unicode, ref uint filesize, ref IntPtr handle, ref IntPtr userdata)
{
// You can ID the file from the name, then do any loading required here
return FMOD.RESULT.OK;
}
private static FMOD.RESULT CLOSECALLBACK(IntPtr handle, IntPtr userdata)
{
// Do any closing required here
return FMOD.RESULT.OK;
}
private static FMOD.RESULT READCALLBACK(IntPtr handle, IntPtr buffer, uint sizebytes, ref uint bytesread, IntPtr userdata)
{
byte[] readbuffer = new byte[sizebytes];
// Populate readbuffer here with raw data
Marshal.Copy(readbuffer, 0, buffer, (int)sizebytes);
return FMOD.RESULT.OK;
}
private static FMOD.RESULT SEEKCALLBACK(IntPtr handle, int pos, IntPtr userdata)
{
// Seek your stream to desired position
return FMOD.RESULT.OK;
}
Implementation:
// Usual init code here...
result = system.setFileSystem(myopen, myclose, myread, myseek, 2048);
ERRCHECK(result);
// Usual create sound code here...

Categories

Resources