Free IntPtr allocated memory after promoting the pointer - c#

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;
}

Related

What is the format of optval for MCAST_JOIN_SOURCE_GROUP setsockopt with IPv6 in Unix?

I'm trying to create a multicast testing tool for my local network. The only feature I don't yet have working is IPv6 SSM on Linux. I've used strace to try and debug and this is the error I'm receiving when I try to join the multicast group:
setsockopt(67, SOL_IPV6, MCAST_JOIN_SOURCE_GROUP, "\3\0\0\0\0\0\0\0\27\0\270\v\0\0\0\0\3778\0\0\0\0\0\0\0\0\0\0\207eC!"..., 264) = -1 EADDRNOTAVAIL (Cannot assign requested address)
Optval = 03000000000000001700B80B00000000FF38000000000000000000008765432100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001700000000000000FE8000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
I am using interface 3, trying to connect to FF38::8765:4321 on port 3000 with FE80::1 as my source. This seems correct to me, any ideas what could be causing the error?
Edit: Here's my code to make the syscall:
[DllImport("libc", SetLastError = true)]
static extern int setsockopt(int sockfd, int level, int optname, void *optval, int size);
fixed(void* data = &joinData[0])
{
setsockopt((int)socket.Handle, 41, 46, data, joinData.Length);
}
and here's my code to populate optval:
byte[] joinBytes;
GroupSourceReqModel v6ssmJoin = new GroupSourceReqModel();
v6ssmJoin.gr_interface = (uint)selections.LocalIp.ScopeId;
SocketAddressIpv6InputModel mGroupIn = new SocketAddressIpv6InputModel
{
sin6_family = (ushort)selections.MulticastAddress.AddressFamily,
sin6_port = (ushort)selections.Port,
sin6_scope_id = 0
};
for (int i = 0; i < selections.MulticastAddress.GetAddressBytes().Length; i++)
{
mGroupIn.sin6_addr[i] = selections.MulticastAddress.GetAddressBytes()[i];
}
SocketAddressStorageModel groupSock = new SocketAddressStorageModel();
byte[] groupSockInData = ConvertToBytes(mGroupIn);
Console.WriteLine(Convert.ToHexString(groupSockInData));
byte* groupSockPointer = (byte*)&groupSock;
for (int i = 0; i < groupSockInData.Length; i++)
{
groupSockPointer[i] = groupSockInData[i]; // Now populate the groupSock object with the byte data of mGroupIn
}
v6ssmJoin.gsr_group = groupSock;
SocketAddressIpv6InputModel sGroupIn = new SocketAddressIpv6InputModel
{
sin6_family = (ushort)selections.SourceAddress.AddressFamily,
sin6_port = 0,
sin6_scope_id = 0
};
for (int i = 0; i < selections.SourceAddress.GetAddressBytes().Length; i++)
{
sGroupIn.sin6_addr[i] = selections.SourceAddress.GetAddressBytes()[i];
}
SocketAddressStorageModel sourceSock = new SocketAddressStorageModel
{
ss_family = (short)selections.SourceAddress.AddressFamily
};
byte[] sourceSockInData = ConvertToBytes(sGroupIn);
byte* sourceSockPointer = (byte*)&sourceSock;
for (int i = 0; i < sourceSockInData.Length; i++)
{
sourceSockPointer[i] = sourceSockInData[i];
}
v6ssmJoin.gsr_source = sourceSock;
joinBytes = ConvertToBytes(v6ssmJoin);
return joinBytes;
public static unsafe byte[] ConvertToBytes<T>(T value) where T : unmanaged
{
byte* pointer = (byte*)&value;
byte[] bytes = new byte[sizeof(T)];
for (int i = 0; i < sizeof(T); i++)
{
bytes[i] = pointer[i];
}
return bytes;
}
If it's relevant, I'm running on kernel version 5.4.0-122-generic.
Address family for IPv6 in Linux is 10, as seen in the kernel source code here which differs from the Windows value that C# uses. In addition, the port value is stored in big endian.

Return SAFEARRAY from c++ to c#

I have a c++ method which creates, fills and returns SAFEARRAY:
SAFEARRAY* TestClass::GetResult(long& size)
{
return GetSafeArrayList(size);
}
How should I export that function in a DLL so that c# could take it
How should I write c# method signature?
I have in c++ something along these lines:
extern "C" __declspec(dllexport) void GetResult(SAFEARRAY*& data, long& size)
{
size = 0;
data = handle->GetResult(size);
}
Is it correct, isn't it?
Thanks for help!
EDIT:
c# call:
public static extern void GetResult(IntPtr handle, [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_USERDEFINED)] TestStruct[] data, ref int size);
Full example of use of a SAFEARRAY(int) C#->C++->C# (so the array is initialized with some data in C#, passed to C++, modified there and returned to C#).
C++:
// For the various _t classes for handling BSTR and IUnknown
#include <comdef.h>
struct ManagedUDT
{
BSTR m_str01;
int m_int01;
~ManagedUDT()
{
::SysFreeString(m_str01);
m_str01 = NULL;
}
};
extern "C" __declspec(dllexport) void GetResult(SAFEARRAY*& data)
{
if (data != NULL)
{
// Begin print content of SAFEARRAY
VARTYPE vt;
HRESULT hr = SafeArrayGetVartype(data, &vt);
if (SUCCEEDED(hr))
{
// To make this code simple, we print only
// SAFEARRAY(VT_I4)
if (vt == VT_I4)
{
int *pVals;
hr = SafeArrayAccessData(data, (void**)&pVals); // direct access to SA memory
if (SUCCEEDED(hr))
{
long lowerBound, upperBound; // get array bounds
SafeArrayGetLBound(data, 1, &lowerBound);
SafeArrayGetUBound(data, 1, &upperBound);
long cnt_elements = upperBound - lowerBound + 1;
for (int i = 0; i < cnt_elements; i++) // iterate through returned values
{
int val = pVals[i];
printf("C++: %d\n", val);
}
SafeArrayUnaccessData(data);
}
else
{
// Error
}
}
}
else
{
// Error
}
// End print content of SAFEARRAY
// Delete the SAFEARRAY if already present
SafeArrayDestroy(data);
data = NULL;
}
{
// Creation of a new SAFEARRAY
SAFEARRAYBOUND bounds;
bounds.lLbound = 0;
bounds.cElements = 10;
data = SafeArrayCreate(VT_I4, 1, &bounds);
int *pVals;
HRESULT hr = SafeArrayAccessData(data, (void**)&pVals); // direct access to SA memory
if (SUCCEEDED(hr))
{
for (ULONG i = 0; i < bounds.cElements; i++)
{
pVals[i] = i + 100;
}
}
else
{
// Error
}
}
}
C#
[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void GetResult([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_I4)] ref int[] ar);
and
var data = new int[] { 1, 2, 3, 4, 5 };
GetResult(ref data);
if (data != null)
{
for (int i = 0; i < data.Length; i++)
{
Console.WriteLine("C#: {0}", data[i]);
}
}
else
{
Console.WriteLine("C#: data is null");
}
Code partially taken from https://stackoverflow.com/a/12484259/613130 and https://stackoverflow.com/a/3735438/613130
SAFEARRAY(VT_RECORD)
It is doable... Very hard... but doable. Please don't do it. You can't hate enough the world to do it. I do hope you don't!
C++:
// For the _com_util
#include <comdef.h>
extern "C"
{
__declspec(dllexport) void GetResultSafeArray(SAFEARRAY *&psa)
{
// All the various hr results should be checked!
HRESULT hr;
// Begin sanity checks
if (psa == NULL)
{
// Error
}
VARTYPE pvt;
hr = ::SafeArrayGetVartype(psa, &pvt);
if (pvt != VT_RECORD)
{
// Error
}
UINT size;
size = ::SafeArrayGetElemsize(psa);
if (size != sizeof(ManagedUDT))
{
// Error
}
// From tests done, it seems SafeArrayGetRecordInfo does a AddRef
_com_ptr_t<_com_IIID<IRecordInfo, NULL> > prinfo;
// The_com_ptr_t<>::operator& is overloaded
hr = ::SafeArrayGetRecordInfo(psa, &prinfo);
// From tests done, it seems GetName returns a new instance of the
// BSTR
// It is ok to use _bstr_t.GetAddress() here, see its description
_bstr_t name1;
hr = prinfo->GetName(name1.GetAddress());
const _bstr_t name2 = _bstr_t(L"ManagedUDT");
if (name1 != name2)
{
// Error
}
// End sanity checks
long lowerBound, upperBound; // get array bounds
hr = ::SafeArrayGetLBound(psa, 1, &lowerBound);
hr = ::SafeArrayGetUBound(psa, 1, &upperBound);
long cnt_elements = upperBound - lowerBound + 1;
// Begin print
ManagedUDT *pVals;
hr = ::SafeArrayAccessData(psa, (void**)&pVals);
printf("C++:\n");
for (int i = 0; i < cnt_elements; ++i)
{
ManagedUDT *pVal = pVals + i;
// If you are using a recent VisualC++, you can
// #include <memory>, and then
//std::unique_ptr<char[]> pstr(_com_util::ConvertBSTRToString(pVal->m_str01));
// and you don't need the char *pstr line and the delete[]
// line
char *pstr = _com_util::ConvertBSTRToString(pVal->m_str01);
printf("%s, %d\n", pstr, pVal->m_int01);
delete[] pstr;
}
hr = ::SafeArrayUnaccessData(psa);
// End print
// Begin free
SAFEARRAYBOUND sab;
sab.lLbound = 0;
sab.cElements = 0;
// SafeArrayRedim will call IRecordInfo::RecordClear
hr = ::SafeArrayRedim(psa, &sab);
// End Free
// Begin create
int numElements = 10;
sab.cElements = numElements;
hr = ::SafeArrayRedim(psa, &sab);
hr = ::SafeArrayAccessData(psa, (void**)&pVals);
for (int i = 0; i < numElements; i++)
{
ManagedUDT *pVal = pVals + i;
char pstr[100];
sprintf(pstr, "Element #%d", i);
pVal->m_str01 = _com_util::ConvertStringToBSTR(pstr);
pVal->m_int01 = 100 + i;
}
hr = ::SafeArrayUnaccessData(psa);
// End create
}
__declspec(dllexport) void GetResultSafeArrayOut(SAFEARRAY *&psa, ITypeInfo *itypeinfo)
{
// All the various hr results should be checked!
HRESULT hr;
// Begin sanity checks
if (psa != NULL)
{
// Begin free
// SafeArrayDestroy will call IRecordInfo::RecordClear
// if necessary
hr = ::SafeArrayDestroy(psa);
// End Free
}
// Begin create
int numElements = 10;
SAFEARRAYBOUND sab;
sab.lLbound = 0;
sab.cElements = numElements;
// The_com_ptr_t<>::operator& is overloaded
_com_ptr_t<_com_IIID<IRecordInfo, NULL> > prinfo;
hr = ::GetRecordInfoFromTypeInfo(itypeinfo, &prinfo);
psa = ::SafeArrayCreateVectorEx(VT_RECORD, 0, numElements, prinfo);
ManagedUDT *pVals;
hr = ::SafeArrayAccessData(psa, (void**)&pVals);
for (int i = 0; i < numElements; i++)
{
ManagedUDT *pVal = pVals + i;
char pstr[100];
sprintf(pstr, "Element #%d", i);
pVal->m_str01 = _com_util::ConvertStringToBSTR(pstr);
pVal->m_int01 = 100 + i;
}
hr = ::SafeArrayUnaccessData(psa);
// End create
}
}
C#:
[ComVisible(true)]
[Guid("BBFE1092-A90C-4b6d-B279-CBA28B9EDDFA")]
[StructLayout(LayoutKind.Sequential)]
public struct ManagedUDT
{
[MarshalAs(UnmanagedType.BStr)]
public string m_str01;
public Int32 m_int01;
}
[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void GetResultSafeArray([MarshalAs(UnmanagedType.SafeArray)] ref ManagedUDT[] array);
[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void GetResultSafeArrayOut([MarshalAs(UnmanagedType.SafeArray)] out ManagedUDT[] array, IntPtr itypeinfo);
[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "GetResultSafeArrayOut")]
static extern void GetResultSafeArrayRef([MarshalAs(UnmanagedType.SafeArray)] ref ManagedUDT[] array, IntPtr itypeinfo);
and
var arr = new[]
{
new ManagedUDT { m_str01 = "Foo", m_int01 = 1},
new ManagedUDT { m_str01 = "Bar", m_int01 = 2},
};
{
Console.WriteLine("C#:");
for (int i = 0; i < arr.Length; i++)
{
Console.WriteLine("{0}, {1}", arr[i].m_str01, arr[i].m_int01);
}
}
{
Console.WriteLine();
var arr2 = (ManagedUDT[])arr.Clone();
GetResultSafeArray(ref arr2);
Console.WriteLine();
Console.WriteLine("C#:");
for (int i = 0; i < arr2.Length; i++)
{
Console.WriteLine("{0}, {1}", arr2[i].m_str01, arr2[i].m_int01);
}
}
{
Console.WriteLine();
ManagedUDT[] arr2;
IntPtr itypeinfo = Marshal.GetITypeInfoForType(typeof(ManagedUDT));
GetResultSafeArrayOut(out arr2, itypeinfo);
Console.WriteLine();
Console.WriteLine("C#:");
for (int i = 0; i < arr2.Length; i++)
{
Console.WriteLine("{0}, {1}", arr2[i].m_str01, arr2[i].m_int01);
}
}
{
Console.WriteLine();
var arr2 = (ManagedUDT[])arr.Clone();
IntPtr itypeinfo = Marshal.GetITypeInfoForType(typeof(ManagedUDT));
GetResultSafeArrayRef(ref arr2, itypeinfo);
Console.WriteLine();
Console.WriteLine("C#:");
for (int i = 0; i < arr2.Length; i++)
{
Console.WriteLine("{0}, {1}", arr2[i].m_str01, arr2[i].m_int01);
}
}
There is a single big caveat for GetResultSafeArray: you must pass from C# at least an empty array (like a new ManagedUDT[0]). This because to create a SAFEARRAY(ManagedUDT) from nothing in C++ you would need a IRecordInfo object. I don't know how to retrieve it from C++. If you already have a SAFEARRAY(ManagedUDT) then clearly it has the IRecordInfo already set, so there is no problem. In the example given, in C++ there are first some sanity checks, then the passed array is printed, then it is emptied, then it is re-filled. The GetResultSafeArrayOut/GetResultSafeArrayRef "cheat": they receive from C# a ITypeInfo pointer (that is easy to retrieve in C#, with Marshal.GetITypeInfoForType()), and from taht the C++ can retrieve the IRecordInfo interface.
Some notes:
I wrote Ansi-charset-C++. Normally for myself I always write Unicode-ready C++ (or directy Unicode-C++, because all the Windows NT support Unicode), but I've noticed that I'm an exception... So in various parts of the code there are conversions BSTR->Ansi->BSTR.
I'm retrieving the HRESULT of all the function calls. They should be checked, and the failure handled.
The most complex thing in C++/COM is knowing when to free something... In general always free/Release() everything! (be it BSTR/IUnknown derived interfaces, ...)
Unless there is a bug, there is no support for this code. Consider it to be a proof of concept. I already lost various hours on it out of curiosity. You break it, you repair it.

How to optimize copying chunks of an array in C#?

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

C# byte array to fixed int pointer

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.

C++ to C# Marshaling

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...

Categories