C++/C# Data Marshalling not working as expected - c#

On the C++ side, I have this:
double* s;
bool GetLeftOutputData(double ** a, int * i)
{
s = new double[4]{ 25,24.0,33.0,57.0 };
*a = s;
*i = 4;
return true;
}
And on the C# side, I have:
[DllImport("MyDLL")]
private static extern bool GetLeftOutputData(out IntPtr ptrResultVerts, out int resultVertLength);
void TestLeftOutputData()
{
IntPtr ptrNativeData;
int itemsLength;
bool success = GetLeftOutputData(out ptrNativeData, out itemsLength);
if (!success)
{
Debug.Log("Faild to get left out data");
return;
}
double[] SArray = new double[itemsLength]; // Where the final data will be stored.
Debug.Log("Length: " + itemsLength);
IntPtr p = ptrNativeData;
for (int i = 0; i < itemsLength; i++)
{
Marshal.PtrToStructure(p, SArray[i]);
p = new IntPtr(p.ToInt64() + Marshal.SizeOf(typeof(double)));
}
}
Code gives no error, but for some reason, double[] array is always filled with 0, i.e. no data is being copied. Where is my mistake?

Related

Sharing array memoryfile C++ to C#

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");

Marshaling Struct Array with Strings Between c# and c++. Strings are empty

I am having the most difficult time marshaling this struct between C# and C++.
What makes it very hard to troubleshoot is that SOMETIMES the strings are populated with data (wtf), but most of the time they are not.
I've tried sending over an Array of structs as well as a IntPtr, but the results are similar, the strings in the struct are almost always empty and I can't figure out what I'm doing wrong in the marshaling. The code is posted below. Any help would be appreciated.
Edit***
Turns out the problem was on the C++ side and all the marshaling stuff was correct. Thanks for the tip Hans. ***
C++:
#pragma pack (push, 1)
typedef struct
{
char FirmwareVers[FS_MAX_FIRMWARE_VER];
char SerialNum[FS_MAX_SERIAL_NUM];
char HardwareVers[FS_MAX_HW_VER];
ULONG StatusFlags;
int LMIndex;
} FS_LMON_STATUS, *PFS_LMON_STATUS;
DllExport int _stdcall FS_GetLMs(PFS_LMON_STATUS pLaunchMonInfo, int MaxLaunchMons, int *pNumLaunchMons)
{
int Cnt;
FS_LMON_STATUS LMStatus;
if(!g_IsInitalized)
return FS_NOT_INITALIZED;
*pNumLaunchMons = 0;
if(MaxLaunchMons == 0)
return FS_ERROR;
for(Cnt = 0; Cnt < MAX_LM_CONNECTIONS; Cnt++)
{
if(g_CreatedClasses.pLMList->GetLMStatus(Cnt, &LMStatus) != FS_SUCCESS)
continue;
if(LMStatus.LMIndex != INVALID_LM_INDEX)
{
memcpy(pLaunchMonInfo, &LMStatus, sizeof(LMStatus));
pLaunchMonInfo++;
(*pNumLaunchMons)++;
MaxLaunchMons--;
if(MaxLaunchMons == 0)
{
return FS_SUCCESS;
}
}
}
return FS_SUCCESS;
}
C#:
[DllImport("FSADLL", SetLastError = false)]
private static extern int FS_GetLMs([Out] IntPtr pLaunchMonInfo, int MaxLaunchMons, ref int pNumLaunchMons);
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] //, Size = 38)]
public struct FS_LMON_STATUS
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = FS_MAX_FIRMWARE_VER)] //10 bytes
public string FirmwareVers;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = FS_MAX_SERIAL_NUM)] // 15 bytes
public string SerialNum;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = FS_MAX_HW_VER)] // 5 bytes
public string HardwareVers;
public uint StatusFlags; //4 bytes
public int LMIndex; // identifies which index //4 bytes
}
const int max_launch_monitors = 8;
FS_LMON_STATUS[] dev_info = new FS_LMON_STATUS[max_launch_monitors];
int num_launch_monitors = 0;
IntPtr pAddr = Marshal.AllocHGlobal(max_launch_monitors * Marshal.SizeOf(typeof(FS_LMON_STATUS)));
Marshal.StructureToPtr(dev_info, pAddr, false);
int result = FS_GetLMs(pAddr, max_launch_monitors, ref num_launch_monitors);
UnityEngine.Debug.Log("Result of FS_GetLMs: " + result);
FS_LMON_STATUS[] device_info = new FS_LMON_STATUS[max_launch_monitors];
//Marshal.Copy(pAddr, device_info, (int)0, num_launch_monitors * (int)Marshal.SizeOf(typeof(FS_LMON_STATUS)));
//Marshal.ReadIntPtr(pAddr, 0);
//device_info = (FS_LMON_STATUS[]) Marshal.PtrToStructure(Marshal.AllocHGlobal(max_launch_monitors * Marshal.SizeOf(typeof(FS_LMON_STATUS[]))), typeof(FS_LMON_STATUS[]));
if (num_launch_monitors > 0)
UnityEngine.Debug.Log("GC2 Device Found.");
else // If there is no devices found, remove the previous device from the holder variable
GC2Device = null;
for (int i = 0; i < num_launch_monitors; i++)
{
device_info[i] = (FS_LMON_STATUS)Marshal.PtrToStructure(pAddr, typeof(FS_LMON_STATUS));
pAddr = new IntPtr(Marshal.SizeOf(typeof(FS_LMON_STATUS)) + pAddr.ToInt64());
}
//*** There will only ever be 1 device in the list until the old SDK is fixed ***
for (int lm_index = 0; lm_index < num_launch_monitors; lm_index++)
{
if (device_info[lm_index].StatusFlags != LM_STATUS_DISCONNECTED)
{
UnityEngine.Debug.Log("device_info.SerialNum: " + device_info[lm_index].SerialNum);
//assign each LM to a LM data structure
LaunchMonitor logical_device = new LaunchMonitor(inst);
logical_device.mLaunchMonitorType = LaunchMonitorType.LAUNCH_MONITOR_TYPE_GC2;
logical_device.mConnectionType = ConnectionType.USB_CONNECTION;
IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(device_info[lm_index]));
Marshal.StructureToPtr(device_info[lm_index], pnt, false);
//Marshal.Copy(device_info[lm_index], dv_info, 0, (uint)Marshal.SizeOf(typeof(FS_LMON_STATUS)));
logical_device.mConnectionToken = pnt;
//GC2Devices.Add(logical_device);
logical_device.Serial = logical_device.GetSerialNumber();
GC2Device = logical_device;
}
}
Turns out the problem was on the C++ side and all the marshaling stuff was correct. Thanks for the tip Hans.

RegEnumKeyEx - Access violation writing location

The situation:
Need to fetch a list of all subkeys of a particular registry key.
Need to access both 32bit and 64bit software keys, so I cannot use the Registry namespace.
Using CSharp in .Net 3.5, and registry functionality from advapi32.dll
I have most of the functionality working but I'm stuck on an error. When it reaches a key that contains values, it will either skip it or throw the following error:
"Unhandled exception at 0x00C819CD in xxxxx.exe: 0xC0000005: Access violation writing location 0x00720077."
If the error occurs, it does not land in either of my catch statements. It hard crashes the program. From what I've read on the forums, I believe it may be an issue with it writing to protected memory but all of the examples I see are for C++
My Declaration (from P/Invoke Interop Assistant):
[DllImportAttribute("advapi32.dll", EntryPoint = "RegEnumKeyExW")]
public static extern int RegEnumKeyExW(
[InAttribute()] IntPtr hKey,
uint dwIndex,
[OutAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)] StringBuilder lpName,
ref uint lpcchName,
IntPtr lpReserved,
IntPtr lpClass,
IntPtr lpcchClass,
IntPtr lpftLastWriteTime);
My Function (obviously a work in progress so it's a bit messy):
static private List<string> GetSubKeys(UIntPtr inHive, String inKeyName, RegSAM in32or64key) {
int hkey = 0;
uint dwIndex = 0;
long enumStatus = 0;
List<string> keys = new List<string>();
try {
uint lResult = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
inKeyName,
0,
(int)RegSAM.QueryValue | (int)RegSAM.EnumerateSubKeys | (int)in32or64key,
out hkey);
if (lResult == 0) {
while (enumStatus == ERROR_SUCCESS) {
StringBuilder lpName = new StringBuilder();
uint lpcchName = 256;
IntPtr lpReserved = IntPtr.Zero;
IntPtr lpClass = IntPtr.Zero;
IntPtr lpcchClass = IntPtr.Zero;
IntPtr lpftLastWriteTime = IntPtr.Zero;
enumStatus = RegEnumKeyExW(
(IntPtr)hkey,
dwIndex,
lpName,
ref lpcchName,
lpReserved,
lpClass,
lpcchClass,
lpftLastWriteTime);
switch (enumStatus) {
case ERROR_SUCCESS:
Console.WriteLine(string.Format("Key Found: {0}", lpName.ToString()));
break;
case ERROR_NO_MORE_ITEMS:
break;
default:
string error = new System.ComponentModel.Win32Exception((int)enumStatus).Message;
Console.WriteLine(string.Format("RegEnumKeyEx Error: {0}", error));
break;
}
dwIndex++;
}
} else {
Console.WriteLine(string.Format("RegOpenKey Error: {0}", lResult));
}
} catch (System.Runtime.InteropServices.COMException ex) {
Console.WriteLine(string.Format("COM Error: {0}", ex.Message));
} catch (Exception ex) {
Console.WriteLine(string.Format("Managed Error: {0}", ex.Message));
} finally {
if (0 != hkey) RegCloseKey(hkey);
}
return keys;
}
#endregion
StringBuilder lpName = new StringBuilder();
uint lpcchName = 256;
You are lying about the StringBuilder's capacity. It is 0, not 256. This will cause the pinvoke call to corrupt the GC heap. This eventually causes a hard crash, typically when a garbage collection takes place. Fix:
uint lpcchName = 256;
StringBuilder lpName = new StringBuilder(lpcchName);
Using the .NET RegistryKey.GetSubKeyNames() method instead would probably be wise.
Use the same way as. net4.0
static void Main(string[] args)
{
string displayName;
List<string> gInstalledSoftware = new List<string>();
using (var localMachine = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
{
var key = localMachine.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", false);
foreach (String keyName in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(keyName);
displayName = subkey.GetValue("DisplayName") as string;
if (string.IsNullOrEmpty(displayName))
continue;
gInstalledSoftware.Add(displayName);
}
}
}
You can try using. net source code to solve this problem. etc.
public class RegistryKey:
IDisposable
{
internal static readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(unchecked((int)0x80000000));
internal static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(unchecked((int)0x80000001));
internal static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(unchecked((int)0x80000002));
internal static readonly IntPtr HKEY_USERS = new IntPtr(unchecked((int)0x80000003));
internal static readonly IntPtr HKEY_PERFORMANCE_DATA = new IntPtr(unchecked((int)0x80000004));
internal static readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(unchecked((int)0x80000005));
private static readonly String[] hkeyNames = new String[] {
"HKEY_CLASSES_ROOT",
"HKEY_CURRENT_USER",
"HKEY_LOCAL_MACHINE",
"HKEY_USERS",
"HKEY_PERFORMANCE_DATA",
"HKEY_CURRENT_CONFIG",
};
public Object GetValue(String name)
{
return InternalGetValue(name, null, false, true);
}
internal Object InternalGetValue(String name, Object defaultValue, bool doNotExpand, bool checkSecurity)
{
Object data = defaultValue;
int type = 0;
int datasize = 0;
int ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, (byte[])null, ref datasize);
if (ret != 0)
{
if (IsPerfDataKey())
{
int size = 65000;
int sizeInput = size;
int r;
byte[] blob = new byte[size];
while (Win32Native.ERROR_MORE_DATA == (r = Win32Native.RegQueryValueEx(hkey, name, null, ref type, blob, ref sizeInput)))
{
if (size == Int32.MaxValue)
{
// ERROR_MORE_DATA was returned however we cannot increase the buffer size beyond Int32.MaxValue
//Win32Error(r, name);
Console.WriteLine(string.Format("[{0}] [{1}]", r,name));
}
else if (size > (Int32.MaxValue / 2))
{
// at this point in the loop "size * 2" would cause an overflow
size = Int32.MaxValue;
}
else
{
size *= 2;
}
sizeInput = size;
blob = new byte[size];
}
if (r != 0)
Console.WriteLine(string.Format("[{0}] [{1}]", r, name));
return blob;
}
else
{
// For stuff like ERROR_FILE_NOT_FOUND, we want to return null (data).
// Some OS's returned ERROR_MORE_DATA even in success cases, so we
// want to continue on through the function.
if (ret != Win32Native.ERROR_MORE_DATA)
return data;
}
}
if (datasize < 0)
{
// unexpected code path
//BCLDebug.Assert(false, "[InternalGetValue] RegQueryValue returned ERROR_SUCCESS but gave a negative datasize");
datasize = 0;
}
switch (type)
{
case Win32Native.REG_NONE:
case Win32Native.REG_DWORD_BIG_ENDIAN:
case Win32Native.REG_BINARY:
{
byte[] blob = new byte[datasize];
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, blob, ref datasize);
data = blob;
}
break;
case Win32Native.REG_QWORD:
{ // also REG_QWORD_LITTLE_ENDIAN
if (datasize > 8)
{
// prevent an AV in the edge case that datasize is larger than sizeof(long)
goto case Win32Native.REG_BINARY;
}
long blob = 0;
//BCLDebug.Assert(datasize==8, "datasize==8");
// Here, datasize must be 8 when calling this
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, ref blob, ref datasize);
data = blob;
}
break;
case Win32Native.REG_DWORD:
{ // also REG_DWORD_LITTLE_ENDIAN
if (datasize > 4)
{
// prevent an AV in the edge case that datasize is larger than sizeof(int)
goto case Win32Native.REG_QWORD;
}
int blob = 0;
// Here, datasize must be four when calling this
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, ref blob, ref datasize);
data = blob;
}
break;
case Win32Native.REG_SZ:
{
if (datasize % 2 == 1)
{
// handle the case where the registry contains an odd-byte length (corrupt data?)
try
{
datasize = checked(datasize + 1);
}
catch (OverflowException e)
{
throw new IOException(("Arg_RegGetOverflowBug"), e);
}
}
char[] blob = new char[datasize / 2];
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, blob, ref datasize);
if (blob.Length > 0 && blob[blob.Length - 1] == (char)0)
{
data = new String(blob, 0, blob.Length - 1);
}
else
{
// in the very unlikely case the data is missing null termination,
// pass in the whole char[] to prevent truncating a character
data = new String(blob);
}
}
break;
case Win32Native.REG_EXPAND_SZ:
{
if (datasize % 2 == 1)
{
// handle the case where the registry contains an odd-byte length (corrupt data?)
try
{
datasize = checked(datasize + 1);
}
catch (OverflowException e)
{
throw new IOException(("Arg_RegGetOverflowBug"), e);
}
}
char[] blob = new char[datasize / 2];
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, blob, ref datasize);
if (blob.Length > 0 && blob[blob.Length - 1] == (char)0)
{
data = new String(blob, 0, blob.Length - 1);
}
else
{
// in the very unlikely case the data is missing null termination,
// pass in the whole char[] to prevent truncating a character
data = new String(blob);
}
if (!doNotExpand)
data = Environment.ExpandEnvironmentVariables((String)data);
}
break;
case Win32Native.REG_MULTI_SZ:
{
if (datasize % 2 == 1)
{
// handle the case where the registry contains an odd-byte length (corrupt data?)
try
{
datasize = checked(datasize + 1);
}
catch (OverflowException e)
{
throw new IOException(("Arg_RegGetOverflowBug"), e);
}
}
char[] blob = new char[datasize / 2];
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, blob, ref datasize);
// make sure the string is null terminated before processing the data
if (blob.Length > 0 && blob[blob.Length - 1] != (char)0)
{
try
{
char[] newBlob = new char[checked(blob.Length + 1)];
for (int i = 0; i < blob.Length; i++)
{
newBlob[i] = blob[i];
}
newBlob[newBlob.Length - 1] = (char)0;
blob = newBlob;
}
catch (OverflowException e)
{
throw new IOException(("Arg_RegGetOverflowBug"), e);
}
blob[blob.Length - 1] = (char)0;
}
IList<String> strings = new List<String>();
int cur = 0;
int len = blob.Length;
while (ret == 0 && cur < len)
{
int nextNull = cur;
while (nextNull < len && blob[nextNull] != (char)0)
{
nextNull++;
}
if (nextNull < len)
{
//BCLDebug.Assert(blob[nextNull] == (char)0, "blob[nextNull] should be 0");
if (nextNull - cur > 0)
{
strings.Add(new String(blob, cur, nextNull - cur));
}
else
{
// we found an empty string. But if we're at the end of the data,
// it's just the extra null terminator.
if (nextNull != len - 1)
strings.Add(String.Empty);
}
}
else
{
strings.Add(new String(blob, cur, len - cur));
}
cur = nextNull + 1;
}
data = new String[strings.Count];
strings.CopyTo((String[])data, 0);
}
break;
case Win32Native.REG_LINK:
default:
break;
}
return data;
}
public String[] GetSubKeyNames()
{
return InternalGetSubKeyNames();
}
public RegistryKey OpenSubKey(string name, bool writable=false)
{
name = FixupName(name); // Fixup multiple slashes to a single slash
SafeRegistryHandle result = null;
int ret = Win32Native.RegOpenKeyEx(hkey,
name,
0,
GetRegistryKeyAccess(writable) | (int)regView,
out result);
if (ret == 0 && !result.IsInvalid)
{
RegistryKey key = new RegistryKey(result, writable, false, remoteKey, false, regView);
key.checkMode = GetSubKeyPermissonCheck(writable);
key.keyName = keyName + "\\" + name;
return key;
}
// Return null if we didn't find the key.
if (ret == Win32Native.ERROR_ACCESS_DENIED || ret == Win32Native.ERROR_BAD_IMPERSONATION_LEVEL)
{
// We need to throw SecurityException here for compatibility reasons,
// although UnauthorizedAccessException will make more sense.
//ThrowHelper.ThrowSecurityException(ExceptionResource.Security_RegistryPermission);
}
return null;
}
private const int MaxKeyLength = 255;
internal unsafe String[] InternalGetSubKeyNames()
{
int subkeys = InternalSubKeyCount();
String[] names = new String[subkeys]; // Returns 0-length array if empty.
if (subkeys > 0)
{
char[] name = new char[MaxKeyLength + 1];
int namelen;
fixed (char* namePtr = &name[0])
{
for (int i = 0; i < subkeys; i++)
{
namelen = name.Length; // Don't remove this. The API's doesn't work if this is not properly initialised.
int ret = Win32Native.RegEnumKeyEx(hkey,
i,
namePtr,
ref namelen,
null,
null,
null,
null);
if (ret != 0)
//Win32Error(ret, null);
Console.WriteLine(ret);
names[i] = new String(namePtr);
}
}
}
return names;
}
internal int InternalSubKeyCount()
{
int subkeys = 0;
int junk = 0;
int ret = Win32Native.RegQueryInfoKey(hkey,
null,
null,
IntPtr.Zero,
ref subkeys, // subkeys
null,
null,
ref junk, // values
null,
null,
null,
null);
if (ret != 0)
//Win32Error(ret, null);
Console.WriteLine(ret);
return subkeys;
}
public static RegistryKey OpenBaseKey(RegistryHive hKey, RegistryView view)
{
return GetBaseKey((IntPtr)((int)hKey), view);
}
internal static RegistryKey GetBaseKey(IntPtr hKey, RegistryView view)
{
int index = ((int)hKey) & 0x0FFFFFFF;
//BCLDebug.Assert(index >= 0 && index < hkeyNames.Length, "index is out of range!");
//BCLDebug.Assert((((int)hKey) & 0xFFFFFFF0) == 0x80000000, "Invalid hkey value!");
bool isPerf = hKey == HKEY_PERFORMANCE_DATA;
// only mark the SafeHandle as ownsHandle if the key is HKEY_PERFORMANCE_DATA.
SafeRegistryHandle srh = new SafeRegistryHandle(hKey, isPerf);
RegistryKey key = new RegistryKey(srh, true, true, false, isPerf, view);
key.checkMode = RegistryKeyPermissionCheck.Default;
key.keyName = hkeyNames[index];
return key;
}
private volatile SafeRegistryHandle hkey = null;
private volatile int state = 0;
private volatile String keyName;
private volatile bool remoteKey = false;
private volatile RegistryKeyPermissionCheck checkMode;
private volatile RegistryView regView = RegistryView.Default;
private const int STATE_DIRTY = 0x0001;
// SystemKey indicates that this is a "SYSTEMKEY" and shouldn't be "opened"
// or "closed".
//
private const int STATE_SYSTEMKEY = 0x0002;
// Access
//
private const int STATE_WRITEACCESS = 0x0004;
// Indicates if this key is for HKEY_PERFORMANCE_DATA
private const int STATE_PERF_DATA = 0x0008;
private RegistryKey(SafeRegistryHandle hkey, bool writable, bool systemkey, bool remoteKey, bool isPerfData, RegistryView view)
{
this.hkey = hkey;
this.keyName = "";
this.remoteKey = remoteKey;
this.regView = view;
if (systemkey)
{
this.state |= STATE_SYSTEMKEY;
}
if (writable)
{
this.state |= STATE_WRITEACCESS;
}
if (isPerfData)
this.state |= STATE_PERF_DATA;
}
private RegistryKeyPermissionCheck GetSubKeyPermissonCheck(bool subkeyWritable)
{
if (checkMode == RegistryKeyPermissionCheck.Default)
{
return checkMode;
}
if (subkeyWritable)
{
return RegistryKeyPermissionCheck.ReadWriteSubTree;
}
else
{
return RegistryKeyPermissionCheck.ReadSubTree;
}
}
static int GetRegistryKeyAccess(bool isWritable)
{
int winAccess;
if (!isWritable)
{
winAccess = Win32Native.KEY_READ;
}
else
{
winAccess = Win32Native.KEY_READ | Win32Native.KEY_WRITE;
}
return winAccess;
}
internal static String FixupName(String name)
{
//BCLDebug.Assert(name!=null,"[FixupName]name!=null");
if (name.IndexOf('\\') == -1)
return name;
StringBuilder sb = new StringBuilder(name);
FixupPath(sb);
int temp = sb.Length - 1;
if (temp >= 0 && sb[temp] == '\\') // Remove trailing slash
sb.Length = temp;
return sb.ToString();
}
private static void FixupPath(StringBuilder path)
{
//Contract.Requires(path != null);
int length = path.Length;
bool fixup = false;
char markerChar = (char)0xFFFF;
int i = 1;
while (i < length - 1)
{
if (path[i] == '\\')
{
i++;
while (i < length)
{
if (path[i] == '\\')
{
path[i] = markerChar;
i++;
fixup = true;
}
else
break;
}
}
i++;
}
if (fixup)
{
i = 0;
int j = 0;
while (i < length)
{
if (path[i] == markerChar)
{
i++;
continue;
}
path[j] = path[i];
i++;
j++;
}
path.Length += j - i;
}
}
#region IDisposable Support
private bool disposedValue = false; // 要检测冗余调用
public void Close()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (hkey != null)
{
if (!IsSystemKey())
{
try
{
hkey.Dispose();
}
catch (IOException)
{
// we don't really care if the handle is invalid at this point
}
finally
{
hkey = null;
}
}
else if (disposing && IsPerfDataKey())
{
// System keys should never be closed. However, we want to call RegCloseKey
// on HKEY_PERFORMANCE_DATA when called from PerformanceCounter.CloseSharedResources
// (i.e. when disposing is true) so that we release the PERFLIB cache and cause it
// to be refreshed (by re-reading the registry) when accessed subsequently.
// This is the only way we can see the just installed perf counter.
// NOTE: since HKEY_PERFORMANCE_DATA is process wide, there is inherent race condition in closing
// the key asynchronously. While Vista is smart enough to rebuild the PERFLIB resources
// in this situation the down level OSes are not. We have a small window between
// the dispose below and usage elsewhere (other threads). This is By Design.
// This is less of an issue when OS > NT5 (i.e Vista & higher), we can close the perfkey
// (to release & refresh PERFLIB resources) and the OS will rebuild PERFLIB as necessary.
SafeRegistryHandle.RegCloseKey(RegistryKey.HKEY_PERFORMANCE_DATA);
}
}
}
private bool IsPerfDataKey()
{
return (this.state & STATE_PERF_DATA) != 0;
}
private bool IsSystemKey()
{
return (this.state & STATE_SYSTEMKEY) != 0;
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
[System.Security.SecurityCritical]
public sealed class SafeRegistryHandle : SafeHandleZeroOrMinusOneIsInvalid
{
[System.Security.SecurityCritical]
internal SafeRegistryHandle() : base(true) { }
[System.Security.SecurityCritical]
public SafeRegistryHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle)
{
SetHandle(preexistingHandle);
}
[System.Security.SecurityCritical]
override protected bool ReleaseHandle()
{
return (RegCloseKey(handle) == Win32Native.ERROR_SUCCESS);
}
[DllImport(Win32Native.ADVAPI32)]
internal static extern int RegCloseKey(IntPtr hKey);
}
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public enum RegistryHive
{
ClassesRoot = unchecked((int)0x80000000),
CurrentUser = unchecked((int)0x80000001),
LocalMachine = unchecked((int)0x80000002),
Users = unchecked((int)0x80000003),
PerformanceData = unchecked((int)0x80000004),
CurrentConfig = unchecked((int)0x80000005),
}
public enum RegistryView
{
Default = 0, // 0x0000 operate on the default registry view
Registry64 = Win32Native.KEY_WOW64_64KEY, // 0x0100 operate on the 64-bit registry view
Registry32 = Win32Native.KEY_WOW64_32KEY, // 0x0200 operate on the 32-bit registry view
};
public enum RegistryKeyPermissionCheck
{
Default = 0,
ReadSubTree = 1,
ReadWriteSubTree = 2
}
public static class Win32Native
{
internal const String ADVAPI32 = "advapi32.dll";
internal const int KEY_WOW64_64KEY = 0x0100; //
internal const int KEY_WOW64_32KEY = 0x0200; //
internal const int ERROR_SUCCESS = 0x0;
internal const int READ_CONTROL = 0x00020000;
internal const int SYNCHRONIZE = 0x00100000;
internal const int STANDARD_RIGHTS_READ = READ_CONTROL;
internal const int STANDARD_RIGHTS_WRITE = READ_CONTROL;
internal const int KEY_QUERY_VALUE = 0x0001;
internal const int KEY_SET_VALUE = 0x0002;
internal const int KEY_CREATE_SUB_KEY = 0x0004;
internal const int KEY_ENUMERATE_SUB_KEYS = 0x0008;
internal const int KEY_NOTIFY = 0x0010;
internal const int KEY_CREATE_LINK = 0x0020;
internal const int KEY_READ = ((STANDARD_RIGHTS_READ |
KEY_QUERY_VALUE |
KEY_ENUMERATE_SUB_KEYS |
KEY_NOTIFY)
&
(~SYNCHRONIZE));
internal const int KEY_WRITE = ((STANDARD_RIGHTS_WRITE |
KEY_SET_VALUE |
KEY_CREATE_SUB_KEY)
&
(~SYNCHRONIZE));
internal const int ERROR_ACCESS_DENIED = 0x5;
internal const int ERROR_BAD_IMPERSONATION_LEVEL = 0x542;
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegOpenKeyEx(SafeRegistryHandle hKey, String lpSubKey,
int ulOptions, int samDesired, out SafeRegistryHandle hkResult);
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegQueryInfoKey(SafeRegistryHandle hKey, [Out]StringBuilder lpClass,
int[] lpcbClass, IntPtr lpReserved_MustBeZero, ref int lpcSubKeys,
int[] lpcbMaxSubKeyLen, int[] lpcbMaxClassLen,
ref int lpcValues, int[] lpcbMaxValueNameLen,
int[] lpcbMaxValueLen, int[] lpcbSecurityDescriptor,
int[] lpftLastWriteTime);
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal unsafe static extern int RegEnumKeyEx(SafeRegistryHandle hKey, int dwIndex,
char* lpName, ref int lpcbName, int[] lpReserved,
[Out]StringBuilder lpClass, int[] lpcbClass,
long[] lpftLastWriteTime);
internal const int ERROR_MORE_DATA = 0xEA;
internal const int REG_NONE = 0; // No value type
internal const int REG_DWORD_BIG_ENDIAN = 5; // 32-bit number
internal const int REG_BINARY = 3; // Free form binary
internal const int REG_QWORD = 11; // 64-bit number
internal const int REG_DWORD = 4; // 32-bit number
internal const int REG_SZ = 1; // Unicode nul terminated string
internal const int REG_EXPAND_SZ = 2; // Unicode nul terminated string
internal const int REG_MULTI_SZ = 7; // Multiple Unicode strings
internal const int REG_LINK = 6; // Symbolic Link (unicode)
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
int[] lpReserved, ref int lpType, [Out] byte[] lpData,
ref int lpcbData);
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
int[] lpReserved, ref int lpType, ref int lpData,
ref int lpcbData);
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
int[] lpReserved, ref int lpType, ref long lpData,
ref int lpcbData);
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
int[] lpReserved, ref int lpType, [Out] char[] lpData,
ref int lpcbData);
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
int[] lpReserved, ref int lpType, [Out]StringBuilder lpData,
ref int lpcbData);
}

C# copy array of structs to array of doubles

[StructLayout(LayoutKind.Sequential)]
public struct Demo
{
double X;
double Y;
}
var data = new Demo[128];
FillWithMeaningfulValues(data);
double[] doubles;
Copy(data, out doubles); // ?
How do I copy the demo array into the doubles array without having to for(...) through each element? In C++, I would use memcpy, but in C# I did not find what I need in Marshal.Copy.
void MethodIDoNotWantToUse(Demo[] demo, out double[] doubles)
{
doubles = new double[demo.Length * 2];
for(int i = 0, j = 0; i < demo.Length; ++i)
{
doubles[j++] = demo[i].X;
doubles[j++] = demo[i].Y;
}
}
void MethodIWouldPreferToUse(Demo[] demo, out double[] doubles)
{
doubles = new double[demo.Length * 2];
memcopy(doubles, demo, demo.Length * 2 * sizeof(double));
}
You'll do something like this. Marshal.Copy do provides you what you need.
Demo[] array = new Demo[2];
array[0] = new Demo {X = 5.6, Y= 6.6};
array[1] = new Demo {X = 7.6, Y = 8.6};
GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
try
{
IntPtr pointer = handle.AddrOfPinnedObject();
double[] copy = new double[array.Length*2];//This length may be calculated
Marshal.Copy(pointer, copy, 0, copy.Length);
}
finally
{
if (handle.IsAllocated)
handle.Free();
}
Since the struct is blittable, the array of the struct is blittable. Therefore you can pin the array of struct and copy into the double array with Marshal.Copy.
void CopyDemoArrayToDoubleArray(Demo[] demo, out double[] doubles)
{
doubles = new double[demo.Length * 2];
GCHandle gch = GCHandle.Alloc(demo, GCHandleType.Pinned);
try
{
IntPtr demoPtr = gch.AddrOfPinnedObject();
Marshal.Copy(demoPtr, doubles, 0, doubles.Length);
}
finally
{
gch.Free();
}
}
You might do well to benchmark this against the simpler for loop that you want to avoid. It is plausible that the for loop will perform perfectly adequately.
It's possible to write a generic method that can convert arrays of any compatible type (by "compatible" I mean "elements must be value types and the size of the elements must be compatible").
You can use P/Invoke to call the Windows API CopyMemory() method.
However, bear in mind that there may not be any performance advantage to doing it this way; you should perform careful timings to be sure.
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
public TOut[] ConvertArray<TIn, TOut>(TIn[] input) where TIn:struct where TOut:struct
{
if (input == null)
throw new ArgumentNullException("input");
int sizeTIn = Marshal.SizeOf(typeof(TIn));
int sizeTOut = Marshal.SizeOf(typeof(TOut));
int sizeBytes = input.Length*sizeTIn;
if ((sizeBytes % sizeTOut) != 0)
throw new ArgumentException("Size of input type is not compatible with size of output type.");
int sizeOut = sizeBytes/sizeTOut;
var output = new TOut[sizeOut];
GCHandle inHandle = GCHandle.Alloc(input, GCHandleType.Pinned);
GCHandle outHandle = GCHandle.Alloc(output, GCHandleType.Pinned);
try
{
IntPtr inPtr = inHandle.AddrOfPinnedObject();
IntPtr outPtr = outHandle.AddrOfPinnedObject();
CopyMemory(outPtr, inPtr, (uint)sizeBytes);
}
finally
{
outHandle.Free();
inHandle.Free();
}
return output;
}
For your example, you could call this like so:
Demo[] test = new Demo[10];
for (int i = 0; i < 10; ++i)
test[i] = new Demo {X = i, Y = i};
var result = ConvertArray<Demo, double>(test);
for (int i = 0; i < 20; ++i)
Console.WriteLine(result[i]);

Select AID command is not working

I am working to an application to read EMV card using C#. I use Winscard.dll .
and i established the conncetion - Selected the reader - connect to card and get ATR .
but when sending comand Slecetd Application usin AID list, I did not recive any data, I expected to receive SW1SW2 as 61XX( where XX the length of data )
I sent the command as 00A4040007A0000000031010 .
The code is:
// Private/Internal Types
[StructLayout(LayoutKind.Sequential)]
internal class SCARD_IO_REQUEST
{
internal uint dwProtocol;
internal int cbPciLength;
public SCARD_IO_REQUEST()
{
dwProtocol = 0;
}
}
public static IntPtr GetPciT0()
{
IntPtr handle = LoadLibrary("Winscard.dll");
IntPtr pci = GetProcAddress(handle, "g_rgSCardT0Pci");
FreeLibrary(handle);
return pci;
}
// public static byte[] GetSendBuffer(string cla, string ins , string p1 ,string p2 , string lc,string body )
public byte[] GetSendBuffer()
{
// Select application 00A4040007A0000000031010
string cla = "00";
string ins = "A4";
string p1 = "04";
string p2 = "00";
string lc = "07";
string body = "A0000000031010";
string script = String.Format("{0}{1}{2}{3}{4}{5}", cla, ins, p1, p2,
lc, body);
byte[] buffer = new byte[ script.Length / 2];
//Console.WriteLine("buffer {0}", buffer);
for (int i = 0; i < script.Length; i = i + 2)
{
string temp = script.Substring(i, 2);
buffer[i / 2] = byte.Parse(temp,
System.Globalization.NumberStyles.HexNumber);
}
return buffer;
}
//=====================================
public void ScardTransmit()
{
SCARD_IO_REQUEST ioRecv = new SCARD_IO_REQUEST();
byte[] pbRecvBuffer = new byte[255];
int pcbRecvLength = 255;
byte[] pbsendBuffer = this.GetSendBuffer();
int pbsendBufLen = pbsendBuffer.Length;
ioRecv.cbPciLength = ioRecv.ToString().Length;
IntPtr SCARD_PCI_T0 = GetPciT0();
uint uintret = SCardTransmit(pCardHandle, ref ioRecv, pbsendBuffer,
pbsendBufLen, SCARD_PCI_T0, pbRecvBuffer, ref pcbRecvLength);
}
Try just sending the following:
0x00A4040000
That should at least return something. The bytes at the end are optional.
They do serve a purpose but just see if you can get something from that first.

Categories

Resources