I have following piece of C++ code that needs to be C Sharped.
int* pData = new int[128];
for(int i = 0; i < 128; i++)
{ pData[i] = i*2 ;}
This pData int* is later passed to a function as void*
Now I need to put all this in C#. What I have done is as follows,
Int32[] tempData = new Int32[128];
for(int i = 0; i < 128; i++)
{ tempData[i] = i*2 ;}
int size = Marshal.SizeOf(tempData[0]) * tempData.Length;
IntPtr ptrData = Marshal.AllocHGlobal(size);
Marshal.Copy(tempData, 0, ptrData, tempData.Length);
Later I pass the ptrData to the C# function.But I get the run time error : Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Thanks in Advance.
int size = sizeof(int) * tempData.Length;
IntPtr ptrData = Marshal.AllocHGlobal(size);
Marshal.Copy(tempData, 0, ptrData, size);
Should do the trick...
Related
I am trying to load a C# assembly with _AppDomainPtr Load_3 method. Do you have some example since I get error:
hr = 0x80131533 : A mismatch has occurred between the runtime type of the array and the sub type recorded in the metadata.
Here is a snippet how do I load the assembly:
static void binarray(SAFEARRAY** output, const char* data, size_t size)
{
SAFEARRAYBOUND Bound;
Bound.lLbound = 0;
Bound.cElements = size;
*output = SafeArrayCreate(VT_R8, 1, &Bound);
double HUGEP *pdFreq;
HRESULT hr = SafeArrayAccessData(*output, (void HUGEP* FAR*)&pdFreq);
if (SUCCEEDED(hr))
{
// copy sample values from data[] to this safearray
for (DWORD i = 0; i < size; i++)
{
*pdFreq++ = data[i];
}
SafeArrayUnaccessData(*output);
}
}
And the call:
hr = spDefaultAppDomain->Load_3(output, &spAssembly);
Anyone used that?
Apparently I've found the problem. I was creating a SafeArray of Real numbers. The correct fix for anyone who needs that is:
static void binarray(SAFEARRAY** output, const unsigned char* data, size_t size)
{
SAFEARRAYBOUND Bound;
Bound.lLbound = 0;
Bound.cElements = size;
// VT_I1
*output = SafeArrayCreate(VT_UI1, 1, &Bound);
//VT_R8
unsigned char *pdFreq;
HRESULT hr = SafeArrayAccessData(*output, (void* FAR*)&pdFreq);
if (SUCCEEDED(hr))
{
// copy sample values from data[] to this safearray
for (DWORD i = 0; i < size; i++)
{
*pdFreq++ = data[i];
}
SafeArrayUnaccessData(*output);
}
}
In C# I fill a binary buffer (1.5 to 2 kB), to which I refer in a C DLL. All goes well (stepping through C says so), until I have to return to C#. At that very last moment, the program crashes (NO exception throwing, just a crash: "Stopped working").
Cr is the C routine, in a DLL.
I work in Visual Studio Community 2017.
Earlier, I passed the data via a string and sscanf_s in C, which worked well, but wanted to speed up things a bit (and learn different things on the way).
The buffer contains all kinds of floats, ints and doubles, which are picked up C-side correctly (stepping says so).
Here is the first piece of C# code:
double[,] MemberEndforces = new double[mbCount, 12];
double[,] Deflection = new double[mbCount + 1, 6];
//double[] Reactions = new double[6];
unsafe
{
using (BinaryWriter binWriter = new BinaryWriter(new MemoryStream()))
{
BuildExportBuffer(binWriter);
var buffer = ((MemoryStream)binWriter.BaseStream).GetBuffer();
info = NativeMethods.Cr(
ref buffer, NrOfMod, Eigenfreqs, ref error,
ref rms_resid, MemberEndforces, Deflection);
} // end using
if (info != 0)
throw new MyException(string.Format(ErrorMessages.SomeError, info));
bool converged = error < tolerance;
...
} // end unsafe
And here folllows the head of the receiving C-routine. Only at the last curly brace, and stepping back to C#, does the crash occur. It does so, with or without the safe{} block.
extern "C"
{
char ** buffer;
//char * next_token;
__declspec(dllexport) int __cdecl Cr(
char **_buffer,
int n,
float * eigenFreq,
double * error,
double * rms_resid,
double * endforces,
double * deflection
)
{ buffer = _buffer;
...
// read stuff from buffer and process it...
return ExitCode;
}
And here is the DLL import:
[DllImport(#"Cr.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "Cr",
CharSet = CharSet.Ansi, BestFitMapping =false,ThrowOnUnmappableChar =true)]
public static extern int Cr([In] ref byte[] buffer,
[In] int n,
float[] eigenfreq,
ref double error,
ref double rms_resid,
double[,] force,
double[,] defl);
So: Why? What do I do wrong ? If there's something wrong in the C-part, it would have shown earlier than the last curly brace, no? The last part of the C code does a lot of freeing malloc-ed blocks (not the buffer!).
According to this post on MSDN multidimensional arrays aren't marshaled when calling an external function, so you must convert the array to a single dimensional one.
As I see those arrays are output buffers, so for calling you can do this:
double[] MemberEndforces = new double[mbCount * 12];
double[] Deflection = new double[(mbCount + 1) * 6];
//...
info = NativeMethods.Cr(
ref buffer, NrOfMod, Eigenfreqs, ref error,
ref rms_resid, MemberEndforces, Deflection);
Then you need to convert those arrays to multidimensional ones once the function has been called:
double[,] mMemberEndforces = new double[mbCount, 12];
double[,] mDeflection = new double[mbCount + 1, 6];
for(int x = 0; x < mbCount; x++)
{
for(int y = 0; y < 12; y++)
mMemberEndforces[x,y] = MemberEndforces[x * 12 + y];
}
for(int x = 0; x < mbCount + 1; x++)
{
for(int y = 0; y < 6; y++)
mDeflection[x,y] = Deflection[x * 6 + y];
}
I found a solution:
I removed the unsafe{}. It's not necessary.
Then I "de-referenced" ref buffer in the call to the C-routine:
using (BinaryWriter binWriter = new BinaryWriter(new MemoryStream()))
{
BuildExportBuffer(binWriter); // fill the buffer with doubles and floats ant ints
var buffer = ((MemoryStream)binWriter.BaseStream).GetBuffer(); // get the buffer's address
info = NativeMethods.Cr( buffer, NrOfMod, Eigenfreqs, ref error, ref rms_resid,
MemberEndforces, Deflection);
.....
etc.
Same thing in the DLLImport, of course.
Also in the C-function I changed some little things:
extern "C"
{
char ** buffer;
__declspec(dllexport) int __cdecl Cr(
char *_buffer, // <== here and
int n,
float * eigenFreq,
double * error,
double * rms_resid,
double * endforces,
double * deflection
)
{
buffer = &_buffer; // <== here.
To show how I read a double from the buffer C-side:
double readd(char **buffer)
{
double *f = (double *) *buffer;
*buffer += 8;
return *f;
}
Works like a charm. I still have to figure out the WHY.
I'm using IntPtr in C#, to get array of object from C++ project.
To do that, i allocated the memory needed with Marshal.AllocHGlobal method, and i'm copying the full array in C++ into the ptr.
The thing is I am promoting the pointer, to move to the next object in the array.
My question is:
Do i have to restore the first value of the IntPtr, before using the Marshal.FreeHGlobal method?
Here is the code
public List<DirEntry> getDirEntries()
{
int dirEntrySize = Marshal.SizeOf(typeof(DirEntry));
int bufferSize = 28 * dirEntrySize;
IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
CppToCsharpAdapter.getDirEntries(this.myDiskPointer, buffer);
DirEntry dirEntry = new DirEntry();
List<DirEntry> dirEntries = new List<DirEntry>();
for (int i = 0; i < 28; i++)
{
Marshal.PtrToStructure(buffer, dirEntry);
buffer += dirEntrySize;
}
Marshal.FreeHGlobal(buffer);
return dirEntries;
}
You have to create a copy of the original pointer which can be used later use. In this case, it is called current:
public List<DirEntry> getDirEntries()
{
int dirEntrySize = Marshal.SizeOf(typeof(DirEntry));
int bufferSize = 28 * dirEntrySize;
IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
CppToCsharpAdapter.getDirEntries(this.myDiskPointer, buffer);
IntPtr current = buffer;
DirEntry dirEntry = new DirEntry();
List<DirEntry> dirEntries = new List<DirEntry>();
for (int i = 0; i < 28; i++)
{
Marshal.PtrToStructure(current, dirEntry);
current += dirEntrySize;
}
Marshal.FreeHGlobal(buffer);
return dirEntries;
}
However, there is another possibility without using an explicit copy of your pointer by using IntPtr.Add():
public List<DirEntry> getDirEntries()
{
int dirEntrySize = Marshal.SizeOf(typeof(DirEntry));
int bufferSize = 28 * dirEntrySize;
IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
CppToCsharpAdapter.getDirEntries(this.myDiskPointer, buffer);
DirEntry dirEntry = new DirEntry();
List<DirEntry> dirEntries = new List<DirEntry>();
for (int i = 0; i < 28; i++)
{
Marshal.PtrToStructure(IntPtr.Add(buffer, i * dirEntrySize), dirEntry);
}
Marshal.FreeHGlobal(buffer);
return dirEntries;
}
Please keep in mind, that your code contains a potential memory leek. You should wrap your code in a try/finally block. In the finally block you free the memory block again if the pointer is not zero:
public List<DirEntry> getDirEntries()
{
int dirEntrySize = Marshal.SizeOf(typeof(DirEntry));
int bufferSize = 28 * dirEntrySize;
IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
try
{
CppToCsharpAdapter.getDirEntries(this.myDiskPointer, buffer);
DirEntry dirEntry = new DirEntry();
List<DirEntry> dirEntries = new List<DirEntry>();
for (int i = 0; i < 28; i++)
{
Marshal.PtrToStructure(IntPtr.Add(buffer, i * dirEntrySize), dirEntry);
}
}
finally
{
if (buffer != IntPtr.Zero)
Marshal.FreeHGlobal(buffer);
}
return dirEntries;
}
I am writing a live-video imaging application and need to speed up this method. It's currently taking about 10ms to execute and I'd like to get it down to 2-3ms.
I've tried both Array.Copy and Buffer.BlockCopy and they both take ~30ms which is 3x longer than the manual copy.
One thought was to somehow copy 4 bytes as an integer and then paste them as an integer, thereby reducing 4 lines of code to one line of code. However, I'm not sure how to do that.
Another thought was to somehow use pointers and unsafe code to do this, but I'm not sure how to do that either.
All help is much appreciated. Thank you!
EDIT: Array sizes are: inputBuffer[327680], lookupTable[16384], outputBuffer[1310720]
public byte[] ApplyLookupTableToBuffer(byte[] lookupTable, ushort[] inputBuffer)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
// Precalculate and initialize the variables
int lookupTableLength = lookupTable.Length;
int bufferLength = inputBuffer.Length;
byte[] outputBuffer = new byte[bufferLength * 4];
int outIndex = 0;
int curPixelValue = 0;
// For each pixel in the input buffer...
for (int curPixel = 0; curPixel < bufferLength; curPixel++)
{
outIndex = curPixel * 4; // Calculate the corresponding index in the output buffer
curPixelValue = inputBuffer[curPixel] * 4; // Retrieve the pixel value and multiply by 4 since the lookup table has 4 values (blue/green/red/alpha) for each pixel value
// If the multiplied pixel value falls within the lookup table...
if ((curPixelValue + 3) < lookupTableLength)
{
// Copy the lookup table value associated with the value of the current input buffer location to the output buffer
outputBuffer[outIndex + 0] = lookupTable[curPixelValue + 0];
outputBuffer[outIndex + 1] = lookupTable[curPixelValue + 1];
outputBuffer[outIndex + 2] = lookupTable[curPixelValue + 2];
outputBuffer[outIndex + 3] = lookupTable[curPixelValue + 3];
//System.Buffer.BlockCopy(lookupTable, curPixelValue, outputBuffer, outIndex, 4); // Takes 2-10x longer than just copying the values manually
//Array.Copy(lookupTable, curPixelValue, outputBuffer, outIndex, 4); // Takes 2-10x longer than just copying the values manually
}
}
Debug.WriteLine("ApplyLookupTableToBuffer(ms): " + sw.Elapsed.TotalMilliseconds.ToString("N2"));
return outputBuffer;
}
EDIT: I've updated the method keeping the same variable names so others can see how the code would translate based on HABJAN's solution below.
public byte[] ApplyLookupTableToBufferV2(byte[] lookupTable, ushort[] inputBuffer)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
// Precalculate and initialize the variables
int lookupTableLength = lookupTable.Length;
int bufferLength = inputBuffer.Length;
byte[] outputBuffer = new byte[bufferLength * 4];
//int outIndex = 0;
int curPixelValue = 0;
unsafe
{
fixed (byte* pointerToOutputBuffer = &outputBuffer[0])
fixed (byte* pointerToLookupTable = &lookupTable[0])
{
// Cast to integer pointers since groups of 4 bytes get copied at once
uint* lookupTablePointer = (uint*)pointerToLookupTable;
uint* outputBufferPointer = (uint*)pointerToOutputBuffer;
// For each pixel in the input buffer...
for (int curPixel = 0; curPixel < bufferLength; curPixel++)
{
// No need to multiply by 4 on the following 2 lines since the pointers are for integers, not bytes
// outIndex = curPixel; // This line is commented since we can use curPixel instead of outIndex
curPixelValue = inputBuffer[curPixel]; // Retrieve the pixel value
if ((curPixelValue + 3) < lookupTableLength)
{
outputBufferPointer[curPixel] = lookupTablePointer[curPixelValue];
}
}
}
}
Debug.WriteLine("2 ApplyLookupTableToBuffer(ms): " + sw.Elapsed.TotalMilliseconds.ToString("N2"));
return outputBuffer;
}
I did some tests, and I managed to achieve max speed by turning my code into unsafe along with using the RtlMoveMemory API. I figured out that Buffer.BlockCopy and Array.Copy were much slower than direct RtlMoveMemory usage.
So, at the end you will end up with something like this:
fixed(byte* ptrOutput= &outputBufferBuffer[0])
{
MoveMemory(ptrOutput, ptrInput, 4);
}
[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
private static unsafe extern void MoveMemory(void* dest, void* src, int size);
EDIT:
Ok, now once when I figured out your logic and when I did some tests, I managed to speed up your method for almost up to 50%. Since you need to copy a small data blocks (always 4 bytes), yes, you were right, RtlMoveMemory wont help here and it's better to copy data as integer. Here is the final solution I came up with:
public static byte[] ApplyLookupTableToBufferV2(byte[] lookupTable, ushort[] inputBuffer)
{
int lookupTableLength = lookupTable.Length;
int bufferLength = inputBuffer.Length;
byte[] outputBuffer = new byte[bufferLength * 4];
int outIndex = 0, curPixelValue = 0;
unsafe
{
fixed (byte* ptrOutput = &outputBuffer[0])
fixed (byte* ptrLookup = &lookupTable[0])
{
uint* lkp = (uint*)ptrLookup;
uint* opt = (uint*)ptrOutput;
for (int index = 0; index < bufferLength; index++)
{
outIndex = index;
curPixelValue = inputBuffer[index];
if ((curPixelValue + 3) < lookupTableLength)
{
opt[outIndex] = lkp[curPixelValue];
}
}
}
}
return outputBuffer;
}
I renamed your method to ApplyLookupTableToBufferV1.
And here are my test result:
int tc1 = Environment.TickCount;
for (int i = 0; i < 200; i++)
{
byte[] a = ApplyLookupTableToBufferV1(lt, ib);
}
tc1 = Environment.TickCount - tc1;
Console.WriteLine("V1: " + tc1.ToString() + "ms");
Result - V1: 998 ms
int tc2 = Environment.TickCount;
for (int i = 0; i < 200; i++)
{
byte[] a = ApplyLookupTableToBufferV2(lt, ib);
}
tc2 = Environment.TickCount - tc2;
Console.WriteLine("V2: " + tc2.ToString() + "ms");
Result - V2: 473 ms
is it possible to somehow cast the type of a pointer created by the fixed() statement?
This is the situation:
I have an array of byte, which i would like to iterate through, however i would like the values to be treated as int, thus having an int* instead of a byte*.
Here's some exemplary code:
byte[] rawdata = new byte[1024];
fixed(int* ptr = rawdata) //this fails with an implicit cast error
{
for(int i = idx; i < rawdata.Length; i++)
{
//do some work here
}
}
Can this be done without having to do the cast inside the iteration?
byte[] rawdata = new byte[1024];
fixed(byte* bptr = rawdata)
{
int* ptr=(int*)bptr;
for(int i = idx; i < rawdata.Length; i++)
{
//do some work here
}
}
I believe you have to go via a byte*. For example:
using System;
class Test
{
unsafe static void Main()
{
byte[] rawData = new byte[1024];
rawData[0] = 1;
rawData[1] = 2;
fixed (byte* bytePtr = rawData)
{
int* intPtr = (int*) bytePtr;
Console.WriteLine(intPtr[0]); // Prints 513 on my box
}
}
}
Note that when iterating, you should use rawData.Length / 4, not rawData.Length if you're treating your byte array as a sequence of 32-bit values.
I found a - seemingly - more elegant and for some reason also faster way of doing this:
byte[] rawData = new byte[1024];
GCHandle rawDataHandle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
int* iPtr = (int*)rawDataHandle.AddrOfPinnedObject().ToPointer();
int length = rawData.Length / sizeof (int);
for (int idx = 0; idx < length; idx++, iPtr++)
{
(*iPtr) = idx;
Console.WriteLine("Value of integer at pointer position: {0}", (*iPtr));
}
rawDataHandle.Free();
This way the only thing i need to do - apart from setting the correct iteration length - is increment the pointer. I compared the code with the one using the fixed statement, and this one is slightly faster.