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

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.

Related

Passing a complex Struct (with inner array of struct) from C# to C++

I'm working on a driver for a scanner. Got dll and header files from provider, aside of a manual in PDF, written in native C++ (dont have source code). Need to use it within a C# project but I'm having problems with the structs (either trying to read or send them).
I got the dll methods using the Command Prompt, demangling them in a website (since it has +100). Of course, I wont use all of them, just the ones I need. Didn't have problems with the ones using primitive data types, in fact, made the scanner turn on/off, scan and such.
My main problem is the following: I need to set some parameters, because with the default ones I'm not getting the needed info (and that's the MOST important thing I need, actually). The only way to do it is with a method that include 2 params: the ID (just an int) and the setting (an struct). That struct has internally not one, but 2 different structs instances (and one of them is an array, within another kind of struct as one of the params). In other words, gonna need to work with 4 different structs.
I declared all my structs, following the template provided in the .h file, and inmported the method. When I try to do a test it keeps giving me an error. I believe the problem is the array of structs. I tried with a normal passing, Marshaling, using a pin to array, changing data type, adding a "MarshalAs" with all bool vars... nothing seems to work.
Been trying to solve this for days already. Dont know what am I doing wrong (because this is my first time importing methods). I read about the C++/Cli thing but never worked with that either.
See code below (I kinda modified a little because of confidentiality of the information)
This is how is defined in the .h file (C++)
// The structs (won't add all parameters, but are basically the same type)
typedef struct _ImParam
{
UINT Format;
UINT Resolution;
UINT ColorDepth;
} IM_PARAM;
typedef struct _sValues
{
UINT Xpos;
UINT Ypos;
UINT Width;
UINT Height;
BOOL Milli;
} S_VALUES;
typedef struct _sProperties
{
BOOL Enable;
S_VALUES Properties;
} S_PROPERTIES;
typedef struct _DevParam
{
BOOL Enable;
UINT Font;
char Symbol;
IM_PARAM Image1;
IM_PARAM Image2;
S_PROPERTIES Properties[10];
UINT FeedMode;
} DevParam;
// more code, comments, etc. etc.
// This is how is defined
BOOL SetParameters( DWORD ID, DevParams DParam )
This is how I build the structs in C#
[StructLayout(LayoutKind.Sequential)]
public struct ImParam
{
public uint Format;
public uint Resolution;
public uint ColorDepth;
public ImParam(uint n)
{
Format = n;
Resolution = 300;
ColorDepth = 256;
}
};
[StructLayout(LayoutKind.Sequential)]
public struct sValues
{
public uint Xpos;
public uint Ypos;
public uint Width;
public uint Height;
public bool Milli;
public sValues(uint n)
{
Xpos = n;
Ypos = n;
Width = n;
Height = n;
Milli = false;
}
};
[StructLayout(LayoutKind.Sequential)]
public struct sProperties
{
public bool Enable;
public sValues Properties;
public sProperties(int n)
{
Enable = false;
Front = false;
Properties = new sValues(n);
}
};
// Commented code is from another attemp
[StructLayout(LayoutKind.Sequential)]
public struct DevParam
{
public bool Enable;
public uint Font;
public char Symbol;
public ImParam Image1;
public ImParam Image2;
public IntPtr Properties;
//public sProperties[] Properties;
public uint FeedMode;
public DeviceParameters(IntPtr SnP) //(int n)
{
Enable = true;
Font = 0;
Symbol = '?';
Image1 = new ImParam(3);
Image2 = new ImParam(3);
Properties = SnP;
/*Properties = new sProperties[n];
*for(int i = 0; i < n; i++)
* Properties[i] = new sProperties(0);*/
FeedMode = 1;
}
};
// .dll file path definition, some methods imported, etc. etc.
[DllImport(path, EntryPoint = "?SetParameters##YGHKU_DevParam###Z")]
public static extern bool SetParameters(int ID, DevParam dParam);
And this is when I do call it (added commented code to show you my attemps)
static void Main(string[] args)
{
bool res = false;
int ID;
sProperties[] SnP = new sProperties[10];
for (int i = 0; i < 10; i++)
SnP[i] = new sProperties(0);
try
{
// Some code to turn on scanner, get ID value and such
/* Attemp1: Passing the struct normaly.
* Result: ArgumentException [HRESULT: 0x80070057 (E_INVALIDARG))]
* try
* {
* DevParam dParam = new DevParam(10);
* res = Class1.SetParameters(ID, dParam);
* Console.WriteLine(res);
* }
* catch (Exception e) { Console.WriteLine(e); }*/
/* Attemp2: Marshaling each element of the array.
* Result: The managed PInvoke signature doesnt mach the destination one
* int S = Marshal.SizeOf(typeof(sProperties));
* DevParam dParam = new DevParam(Marshal.AllocHGlobal(SnP.Length*S));
* IntPtr ptr = dParam.Properties;
* for (int i = 0; i < SnP.Length; i++)
* {
* Marshal.StructureToPtr(SnP[i], ptr, false);
* ptr += S;
* }
* try
* {
* res = Class1.SetDevParam(ID, dParam);
* Console.WriteLine(res);
* }
* finally { Marshal.FreeHGlobal(dParam.sProperties); }*/
/* Attemp3: Adding a Pin Pointer to struct
* Result: Exception (Object has no primitive data and it can't
* be transfered into bits blocks) */
GCHandle SpHandle = GCHandle.Alloc(SnP, GCHandleType.Pinned);
try
{
DevParam dParam = new DevParam(SpHandle.AddrOfPinnedObject());
res = Class1.SetParameters(ID, dParam);
Console.WriteLine(res);
}
catch (Exception e) { Console.WriteLine(e); }
finally { SpHandle.Free(); }
// More code for testing other methods and blahblahblah
}
catch (Exception e) { Console.WriteLine(e); }
Console.WriteLine("Finished");
Console.ReadKey();
}
What do I expect? Getting just a boolean result to see if method executed sucessfully (and of course, if true, scanner should have defined the new parameters)
What do I get? A bunch of exceptions.
Please, any help would be great. Thanks in advance.
PD: Sorry for that long post.
PD2: I'm quite rockie, so please try to explain it "for dummies"
Thanks Hans. Seems it worked!
Just modiffied the struct as suggested:
[StructLayout(LayoutKind.Sequential)]
public struct DevParam
{
public bool Enable;
public uint Font;
public char Symbol;
public ImParam Image1;
public ImParam Image2;
//public IntPtr Properties;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public sProperties[] Properties;
public uint FeedMode;
public DeviceParameters(int n) //(IntPtr SnP)
{
Enable = true;
Font = 0;
Symbol = '?';
Image1 = new ImParam(3);
Image2 = new ImParam(3);
//Properties = SnP;
Properties = new sProperties[n];
for(int i = 0; i < n; i++)
Properties[i] = new sProperties(0);
FeedMode = 1;
}
};
And used the "Attemp1" code.

DeviceIoControlCE for I2C

I have been banging my head against a problem for days now. I would like your help.
I am trying to interface to I2C from a board running Windows CE7. The board is a Boundary Devices Nitrogen6X.
I am trying to code this in C#.
After a lot of googling and trial and error I can now do almost everything with the I2C (by that I mean I wrapped most commands in methods that work). Of course, the one thing that I cannot do yet is Reading/Writing. I have been trying a few different implementations, porting C and C++ code that supposedly worked. To no avail. Currently I am putting more effort in the two implementations I will copy here.
Neither of these implementations work for me. Both enter the error management portion, and both report error number 87 (ERROR_INVALID_PARAMETER).
Does anyone have experience on these kind of issues? could someone point out what I am doing wrong?
Edit 1: I should probably mention that I am trying to "see" some signals on the SDA and SCL pins of I2C3: of the board by simply plugging an oscilloscope to them. There is no actual device connected on the I2C bus. I would expect this to give me some sort of error after the first byte (addres+Read/Write) has been sent, because no acknowledge bit would be received. However, I see that error 87 in my code, and no change on the signals as seen from the scope (both remain high on idle).
(Code snippets follow)
The first one uses pointers and stuff, and is probably closer to C++ code:
StructLayout(LayoutKind.Sequential)]
unsafe public struct UNSAFE_I2C_PACKET
{
//[MarshalAs(UnmanagedType.U1)]
public byte byAddr; //I2C slave device address
//[MarshalAs(UnmanagedType.U1)]
public byte byRw; //Read = I2C_Read or Write = I2C_Write
//[MarshalAs(UnmanagedType.LPArray)]
public byte* pbyBuf; //Message Buffer
//[MarshalAs(UnmanagedType.U2)]
public Int16 wLen; //Message Buffer Length
//[MarshalAs(UnmanagedType.LPStruct)]
public int* lpiResult; //Contain the result of last operation
}
[StructLayout(LayoutKind.Sequential)]
unsafe public struct UNSAFE_I2C_TRANSFER_BLOCK
{
//public I2C_PACKET pI2CPackets;
public UNSAFE_I2C_PACKET* pI2CPackets;
public Int32 iNumPackets;
}
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
unsafe internal static extern int DeviceIoControlCE(
IntPtr hDevice, //file handle to driver
uint dwIoControlCode, //a correct call to CTL_CODE
[In, Out]byte* lpInBuffer,
uint nInBufferSize,
byte* lpOutBuffer,
uint nOutBufferSize,
uint* lpBytesReturned,
int* lpOverlapped);
unsafe public void ReadI2C(byte* pBuf, int count)
{
int ret;
int iResult;
UNSAFE_I2C_TRANSFER_BLOCK I2CXferBlock = new UNSAFE_I2C_TRANSFER_BLOCK();
UNSAFE_I2C_PACKET i2cPckt = new UNSAFE_I2C_PACKET();
//fixed (byte* p = pBuf)
{
i2cPckt.pbyBuf = pBuf;// p;
i2cPckt.wLen = (Int16)count;
i2cPckt.byRw = I2C_READ;
i2cPckt.byAddr = BASE;
i2cPckt.lpiResult = &iResult;
I2CXferBlock.iNumPackets = 1;
//fixed (I2C_PACKET* pck = &i2cPckt)
{
I2CXferBlock.pI2CPackets = &i2cPckt; // pck;
//fixed (I2C_TRANSFER_BLOCK* tBlock = &I2CXferBlock)
{
if (DeviceIoControlCE(_i2cFile,
I2C_IOCTL_TRANSFER,
(byte*)&I2CXferBlock,//tBlock,
(uint)sizeof(UNSAFE_I2C_TRANSFER_BLOCK),//Marshal.SizeOf(I2CXferBlock),
null,
0,
null,
null) == 0)
{
int error = GetLastError();
diag("Errore nella TRANSFER");
diag(error.ToString());
}
}
}
}
}
The second option I am working on marshals stuff around between managed and unmanaged:
[StructLayout(LayoutKind.Sequential)]
public struct I2C_PACKET
//public class I2C_PACKET
{
//[MarshalAs(UnmanagedType.U1)]
public Byte byAddr; //I2C slave device address
//[MarshalAs(UnmanagedType.U1)]
public Byte byRw; //Read = I2C_Read or Write = I2C_Write
//[MarshalAs(UnmanagedType.LPArray)]
public IntPtr pbyBuf; //Message Buffer
//[MarshalAs(UnmanagedType.U2)]
public Int16 wLen; //Message Buffer Length
//[MarshalAs(UnmanagedType.LPStruct)]
public IntPtr lpiResult; //Contain the result of last operation
}
[StructLayout(LayoutKind.Sequential)]
public struct I2C_TRANSFER_BLOCK
{
//public I2C_PACKET pI2CPackets;
//[MarshalAs(UnmanagedType.LPArray)]
public IntPtr pI2CPackets;
//[MarshalAs(UnmanagedType.U4)]
public Int32 iNumPackets;
}
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
internal static extern int DeviceIoControlCE(
IntPtr hDevice, //file handle to driver
uint dwIoControlCode, //a correct call to CTL_CODE
[In] IntPtr lpInBuffer,
uint nInBufferSize,
[Out] IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);
unsafe public void ReadI2C(byte[] buffer)
{
int count = buffer.Length;
I2C_TRANSFER_BLOCK I2CXFerBlock = new I2C_TRANSFER_BLOCK();
I2C_PACKET I2CPckt = new I2C_PACKET();
I2CPckt.byAddr = BASE;
I2CPckt.byRw = I2C_READ;
I2CPckt.wLen = (Int16)count;
I2CPckt.lpiResult = Marshal.AllocHGlobal(sizeof(int));
I2CPckt.pbyBuf = Marshal.AllocHGlobal(count);
//GCHandle packet = GCHandle.Alloc(I2CPckt, GCHandleType.Pinned);
I2CXFerBlock.iNumPackets = 1;
I2CXFerBlock.pI2CPackets = Marshal.AllocHGlobal(Marshal.SizeOf(I2CPckt)); //(Marshal.SizeOf(typeof(I2C_PACKET)));// //(sizeof(I2C_PACKET));//
Marshal.StructureToPtr(I2CPckt, I2CXFerBlock.pI2CPackets, false);
//I2CXFerBlock.pI2CPackets = packet.AddrOfPinnedObject();
//GCHandle xferBlock = GCHandle.Alloc(I2CXFerBlock, GCHandleType.Pinned);
IntPtr xfer = Marshal.AllocHGlobal(Marshal.SizeOf(I2CXFerBlock)); //(sizeof(I2C_TRANSFER_BLOCK)); //
Marshal.StructureToPtr(I2CXFerBlock, xfer, false);
//IntPtr xfer = xferBlock.AddrOfPinnedObject();
uint size = (uint)sizeof(I2C_TRANSFER_BLOCK);//Marshal.SizeOf(I2CXFerBlock);
uint getCnt = 0;
if ((DeviceIoControlCE(_i2cFile,
I2C_IOCTL_TRANSFER,
xfer,
size,
xfer, //IntPtr.Zero,
size, //0,
out getCnt,
IntPtr.Zero)) == 0)
{
int error = GetLastError();
diag("Errore nella TRANSFER.");
diag(error.ToString());
}
else
{
//success
I2CXFerBlock = (I2C_TRANSFER_BLOCK)Marshal.PtrToStructure(xfer, typeof(I2C_TRANSFER_BLOCK));
I2CPckt = (I2C_PACKET)Marshal.PtrToStructure(I2CXFerBlock.pI2CPackets, typeof(I2C_PACKET));
Marshal.Copy(I2CPckt.pbyBuf, buffer, 0, count);
diag("Success in TRANSFER: " + buffer[0].ToString());
}
Marshal.FreeHGlobal(I2CPckt.pbyBuf);
Marshal.FreeHGlobal(I2CXFerBlock.pI2CPackets);
Marshal.FreeHGlobal(xfer);
//packet.Free();
//xferBlock.Free();
}
Edit 2: The (supposedly) working code I have (which I am unable to run) comes from drivers I have been given, which might be partially proprietary (hence I cannot share). However I found online the header for an I2C bus, that contains the following definition:
#define I2C_MACRO_TRANSFER(hDev, pI2CTransferBlock) \
(DeviceIoControl(hDev, I2C_IOCTL_TRANSFER, (PBYTE) pI2CTransferBlock, sizeof(I2C_TRANSFER_BLOCK), NULL, 0, NULL, NULL))
I initially tried giving "null" to parameters as it's done here, but I still got the same error code.
Edit 3: From the same driver, the struct definitions:
// I2C Packet
typedef struct
{
BYTE byAddr; // I2C slave device address for this I2C operation
BYTE byRW; // Read = I2C_READ or Write = I2C_WRITE
PBYTE pbyBuf; // Message Buffer
WORD wLen; // Message Buffer Length
LPINT lpiResult; // Contains the result of last operation
} I2C_PACKET, *PI2C_PACKET;
// I2C Transfer Block
typedef struct
{
I2C_PACKET *pI2CPackets;
INT32 iNumPackets;
} I2C_TRANSFER_BLOCK, *PI2C_TRANSFER_BLOCK;
Edit 4: I tried implementing version passing a ref to my structures, as #ctacke suggested in his comment. I still get the same error, so I guess I must have done womthing different from the way he thought it. Here is the snippet:
[StructLayout(LayoutKind.Sequential)]
public struct REF_I2C_PACKET //public class REF_I2C_PACKET //
{
//[MarshalAs(UnmanagedType.U1)]
public Byte byAddr; //I2C slave device address
//[MarshalAs(UnmanagedType.U1)]
public Byte byRw; //Read = I2C_Read or Write = I2C_Write
//[MarshalAs(UnmanagedType.LPArray)]
public IntPtr pbyBuf; //Message Buffer
//[MarshalAs(UnmanagedType.U2)]
public Int16 wLen; //Message Buffer Length
//[MarshalAs(UnmanagedType.LPStruct)]
public IntPtr lpiResult; //Contain the result of last operation
}
[StructLayout(LayoutKind.Sequential)]
public struct REF_I2C_TRANSFER_BLOCK //public class REF_I2C_TRANSFER_BLOCK //
{
//public I2C_PACKET pI2CPackets;
public IntPtr pI2CPackets;
//[MarshalAs(UnmanagedType.U4)]
public Int32 iNumPackets;
//[MarshalAs(UnmanagedType.LPArray)]
//[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStruct, SizeConst = 2)]
//public REF_I2C_PACKET[] pI2CPackets;
}
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
unsafe internal static extern int DeviceIoControlCE(
IntPtr hDevice, //file handle to driver
uint dwIoControlCode, //a correct call to CTL_CODE
//[MarshalAs(UnmanagedType.AsAny)]
//[In] object lpInBuffer, //
ref REF_I2C_TRANSFER_BLOCK lpInBuffer,
uint nInBufferSize,
byte* lpOutBuffer, //ref REF_I2C_TRANSFER_BLOCK lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned, //uint* lpBytesReturned,
int* lpOverlapped);
unsafe public void RefReadI2C(byte[] buffer)
{
int count = buffer.Length;
REF_I2C_TRANSFER_BLOCK I2CXFerBlock = new REF_I2C_TRANSFER_BLOCK();
REF_I2C_PACKET[] I2CPckt = new REF_I2C_PACKET[2];
I2CPckt[0] = new REF_I2C_PACKET();
I2CPckt[1] = new REF_I2C_PACKET();
I2CPckt[0].byAddr = BASE;
I2CPckt[0].byRw = I2C_READ;
I2CPckt[0].wLen = (Int16)count;
I2CPckt[0].lpiResult = Marshal.AllocHGlobal(sizeof(int));
I2CPckt[0].pbyBuf = Marshal.AllocHGlobal(count);
Marshal.Copy(buffer, 0, I2CPckt[0].pbyBuf, count);
I2CPckt[1].byAddr = BASE;
I2CPckt[1].byRw = I2C_READ;
I2CPckt[1].wLen = (Int16)count;
I2CPckt[1].lpiResult = Marshal.AllocHGlobal(sizeof(int));
I2CPckt[1].pbyBuf = Marshal.AllocHGlobal(count);
Marshal.Copy(buffer, 0, I2CPckt[0].pbyBuf, count);
I2CXFerBlock.iNumPackets = 2;
I2CXFerBlock.pI2CPackets = Marshal.AllocHGlobal(Marshal.SizeOf(I2CPckt[0])*I2CPckt.Length);
uint size = (uint)Marshal.SizeOf(I2CXFerBlock); //sizeof(REF_I2C_TRANSFER_BLOCK);//Marshal.SizeOf(I2CXFerBlock);
//size += (uint)(Marshal.SizeOf(I2CPckt[0]) * I2CPckt.Length);
uint getCnt = 0;
if ((DeviceIoControlCE(_i2cFile,
I2C_IOCTL_TRANSFER,
ref I2CXFerBlock,
size,
null, //IntPtr.Zero,
0, //0,
out getCnt,
null)) == 0)
{
int error = GetLastError();
diag("Errore nella TRANSFER.");
diag(error.ToString());
}
else
{
//success
I2CPckt = (REF_I2C_PACKET[])Marshal.PtrToStructure(I2CXFerBlock.pI2CPackets, typeof(REF_I2C_PACKET[]));
Marshal.Copy(I2CPckt[0].pbyBuf, buffer, 0, count);
diag("Success in TRANSFER: " + buffer[0].ToString());
}
Marshal.FreeHGlobal(I2CPckt[0].pbyBuf);
Marshal.FreeHGlobal(I2CPckt[0].lpiResult);
}
Edit 5:
I found online (http://em-works.googlecode.com/svn/trunk/WINCE600/PLATFORM/COMMON/SRC/SOC/COMMON_FSL_V2_PDK1_9/I2C/PDK/i2c_io.cpp) The following code:
BOOL I2C_IOControl(DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn,
DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut,
PDWORD pdwActualOut)
{
/*stuff*/
case I2C_IOCTL_TRANSFER:
{
#define MARSHAL 1
#if MARSHAL
DuplicatedBuffer_t Marshalled_pInBuf(pBufIn, dwLenIn, ARG_I_PTR);
pBufIn = reinterpret_cast<PBYTE>( Marshalled_pInBuf.ptr() );
if( (dwLenIn > 0) && (NULL == pBufIn) )
{
return FALSE;
}
#endif
I2C_TRANSFER_BLOCK *pXferBlock = (I2C_TRANSFER_BLOCK *) pBufIn;
if (pXferBlock->iNumPackets<=0)
{
return FALSE;
}
#if MARSHAL
MarshalledBuffer_t Marshalled_pPackets(pXferBlock->pI2CPackets,
pXferBlock->iNumPackets*sizeof(I2C_PACKET),
ARG_I_PTR);
I2C_PACKET *pPackets = reinterpret_cast<I2C_PACKET *>(Marshalled_pPackets.ptr());
if( (NULL == pPackets) )
{
return FALSE;
}
#else
I2C_PACKET *pPackets = pXferBlock->pI2CPackets;
#endif
#if MARSHAL
struct Marshalled_I2C_PACKET
{
MarshalledBuffer_t *pbyBuf;
MarshalledBuffer_t *lpiResult;
} *Marshalled_of_pPackets;
Marshalled_of_pPackets = new Marshalled_I2C_PACKET[pXferBlock->iNumPackets];
if (Marshalled_of_pPackets==0)
{
return FALSE;
}
MarshalledBuffer_t *pMarshalled_ptr;
int i;
// Map pointers for each packet in the array
for (i = 0; i < pXferBlock->iNumPackets; i++)
{
switch( pPackets[i].byRW & I2C_METHOD_MASK )
{
case I2C_RW_WRITE:
pMarshalled_ptr = new MarshalledBuffer_t(
pPackets[i].pbyBuf,
pPackets[i].wLen,
ARG_I_PTR,
FALSE, FALSE);
if (pMarshalled_ptr ==0)
{
bRet = FALSE;
goto cleanupPass1;
}
if (pMarshalled_ptr->ptr()==0)
{
bRet = FALSE;
delete pMarshalled_ptr;
goto cleanupPass1;
}
break;
case I2C_RW_READ:
pMarshalled_ptr = new MarshalledBuffer_t(
pPackets[i].pbyBuf,
pPackets[i].wLen,
ARG_O_PTR, FALSE, FALSE);
if (pMarshalled_ptr ==0)
{
bRet = FALSE;
goto cleanupPass1;
}
if (pMarshalled_ptr->ptr()==0)
{
bRet = FALSE;
delete pMarshalled_ptr;
goto cleanupPass1;
}
break;
default:
{
bRet = FALSE;
goto cleanupPass1;
}
}
pPackets[i].pbyBuf = reinterpret_cast<PBYTE>(pMarshalled_ptr->ptr());
Marshalled_of_pPackets[i].pbyBuf = pMarshalled_ptr;
}
for (i = 0; i < pXferBlock->iNumPackets; i++)
{
pMarshalled_ptr = new MarshalledBuffer_t(
pPackets[i].lpiResult, sizeof(INT),
ARG_O_PDW, FALSE, FALSE);
if (pMarshalled_ptr ==0)
{
bRet = FALSE;
goto cleanupPass2;
}
if (pMarshalled_ptr->ptr()==0)
{
bRet = FALSE;
delete pMarshalled_ptr;
goto cleanupPass2;
}
pPackets[i].lpiResult = reinterpret_cast<LPINT>(pMarshalled_ptr->ptr());
Marshalled_of_pPackets[i].lpiResult = pMarshalled_ptr;
}
#endif
bRet = pI2C->ProcessPackets(pPackets, pXferBlock->iNumPackets);
#if MARSHAL
DEBUGMSG (ZONE_IOCTL|ZONE_FUNCTION, (TEXT("I2C_IOControl:I2C_IOCTL_TRANSFER -\r\n")));
i = pXferBlock->iNumPackets;
cleanupPass2:
for (--i; i>=0; --i)
{
delete Marshalled_of_pPackets[i].lpiResult;
}
i = pXferBlock->iNumPackets;
cleanupPass1:
for (--i; i>=0; --i)
{
delete Marshalled_of_pPackets[i].pbyBuf;
}
delete[] Marshalled_of_pPackets;
#endif
break;
}
/*stuff*/
}
I cannot claim to understand 100% of it, but from the Windows naming conventions (http://msdn.microsoft.com/en-us/library/windows/desktop/aa378932(v=vs.85).aspx) it would appear that the size parameter I should send is the total number of bytes of my transfer, including everything. I have tried to figure that number out myself, but I have so far not been able to. Alternatively, I guess it would be possible to try and do something to the structures I have to turn them into a byte array. Only I guess that it would need to have a specific order of the bytes in it for the system to understand it.
Can anyone pitch in on that?

Error 299 when trying to read process memory

i'm having some problem with reading process's memory, all i get is error 299, sometimes error 5/6, i'm new to memory reading / writing and can use any help.
This is what i have so far :
private void ScanMemory()
{
uint PID;
GetWindowThreadProcessId(GetWindowHandle(), out PID);
label3.Text = "" + (int)PID;
int valueToSearch = 4;
List<int> matchAddresses = new List<int>();
long MaxAddress = 0x7fffffff;
long address = 0;
do
{
MEMORY_BASIC_INFORMATION32 m;
IntPtr Handle = OpenProcess((int)ProcessAccessFlags.All, false, (int)PID);
uint result = VirtualQueryEx((int)Handle, (int)address, out m, (int)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION32)));
if (address == (long)m.BaseAddress + (long)m.RegionSize)
break;
address = (long)m.BaseAddress + (long)m.RegionSize;
SearchIntSizeValue(Handle, (int)m.BaseAddress, (int)m.RegionSize, valueToSearch, matchAddresses);
} while (address <= MaxAddress);
foreach (int res in matchAddresses)
{
listBox1.Items.Add(res);
}
}
public void SearchIntSizeValue(IntPtr hProcess, int startAddress, int endAddress, int valueToSearch, List<int> addresses)
{
byte[] buffer = new byte[4];
IntPtr bytesread;
while (startAddress < endAddress)
{
ReadProcessMemory(hProcess, (IntPtr)startAddress, buffer, 4, out bytesread);
int res = BitConverter.ToInt32(buffer, 0);
if (res == valueToSearch)
{
addresses.Add(startAddress);
}
else
{
int le;
if ((le = Marshal.GetLastWin32Error()) != 0)
{
}
}
startAddress += 4;
}
}
[StructLayout(LayoutKind.Sequential)]
struct MEMORY_BASIC_INFORMATION32
{
public uint BaseAddress;
public uint AllocationBase;
public int AllocationProtect;
public uint RegionSize;
public int State;
public int Protect;
public int lType;
}
i'm reading size of int at the moment, not really working :|, from reading in google, i saw there is this thing with privilege , though, i run vs2010 with Admin rights on windows 7, i hope it's enough information for you to spot my problme, thanks in advance!
Me helped solution on www.codeproject.com: Solving-Problems-of-Monitoring-Standard-Output.
Solution protect application from additional deadlocks that Microsoft does not mention in their documentation.

Pinvoke C# from C++ dll using DLLimport in C#

C++ Function header in DLL this two function to get some information about the wifi stations around me using win mobile 6.5 device and i need to invoke them to use them in C# code
// (adapter names , pointer to destination buffer ,and the size , returned structs)
bool __declspec(dllexport) GetBBSIDs(LPWSTR pAdapter, struct BSSIDInfo *pDest, DWORD &dwBufSizeBytes, DWORD &dwReturnedItems);
bool __declspec(dllexport) RefreshBSSIDs(LPWSTR pAdapter);
bool __declspec(dllexport) GetAdapters(LPWSTR pDest, DWORD &dwBufSizeBytes);
C# sample
[DllImport(#"\Storage Card\Work\Beaad.dll", EntryPoint = "GetAdapters", SetLastError = true)]
public static extern bool getAdapters([MarshalAs(UnmanagedType.LPWStr)] String buf, ref UInt32 dwBufSizeBytes);
[DllImport(#"\Storage Card\Work\Beaad.dll", EntryPoint = "RefreshBSSIDs", SetLastError = true)]
public static extern bool refreshBSSIDs([MarshalAs(UnmanagedType.LPWStr)]String buf);
[DllImport(#"\Storage Card\Work\Beaad.dll", EntryPoint = "GetBBSIDs", SetLastError = true)]
public static extern bool getBBSIDs([MarshalAs(UnmanagedType.LPWStr)]String buf,BSSIDInfo [] nfo, ref UInt32 dwBufSizeBytes, ref UInt32 dwReturnedItems);
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)]
public struct BSSIDInfo
{
public byte[] BSSID; //mac
public char[] SSID;
public BSSIDInfo(byte[]bs,char[] ss)
{
this.RSSI = 0;
this.Infastructure = 0;
this.Channel = 0;
this.Auth = 0;
bs = new byte[6];
ss = new char[32];
BSSID = bs;
SSID = ss;
}
public int RSSI;
public int Channel;
public int Infastructure;
public int Auth;
}
public static byte[] StrToByteArray(string str)
{
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
return encoding.GetBytes(str);
}
public static char[] c = new char[1024];
string buf = new string(c);
public void button1_Click(object sender, EventArgs e)
{
BSSIDInfo[] nfo = new BSSIDInfo[128];
byte[] bytee=StrToByteArray(buf);
UInt32 dwsize= new UInt32();
UInt32 dwTmp = new UInt32();
UInt32 dwCount = new UInt32();
dwTmp = Convert.ToUInt32(Marshal.SizeOf(typeof(BSSIDInfo)) * nfo.Length);
dwCount =0;
dwsize=Convert.ToUInt32(bytee.Length);
if (false == getAdapters(buf,ref dwsize) || dwsize == 0)
{
label1.Text = "no adabters";
}
else
{
String [] strList=new String[15];
if (buf.Contains(',') == false)// one adapter
{
textBox1.Text = buf;
}
else
{
strList = buf.Split(',');
for (int i = 0; i < strList.Length; i++)
{
textBox1.Text+= strList[i]+Environment.NewLine;
}
}
if (refreshBSSIDs(buf) && getBBSIDs(buf, nfo, ref dwTmp, ref dwCount) && dwCount > 0)
{
//refreshBSSIDs(buf) &&
for (int i = 0; i < dwCount; i++)
{
textBox2.Text += nfo.GetValue(i).ToString() + Environment.NewLine;
}
}
else
{
//make another thing
}
}
}
and when i put this dll on the mobile and the C# app.exe the first function that named as Getadapters(..) return to me the name of the adapter in the first textbox1 then the app stopped and give me not supported exception when the mobile tries to execute the other two function that named as refreshBSSID() and getBSSIDs() so what is the problem ? or is there another solution to get this information (BSSID ,SS ..etc) ?
C++ by default unless changed uses a caller( Cdecl ) calling convention. Your C++ code does not change the calling convention. Your C# code by default ( unless you change it ) will use a callee convention ( StdCall ).
While this might not be exactly the problem your having it still is technically incorrect. Even if you were to fix your current problem you likely will end up having a problem because of the calling convention.
I am going to guess your C# BSSIDInfo structure does not match the C++ structure. Why do the method StrToByteArray when all it does is GetBytes on the given string...
when the mobile tries to execute the
other two function that named as
refreshBSSID() and getBSSIDs() so what
is the problem ? or is there another
solution to get this information
I thought I knew the reason took another look and I was wrong.

c# interop with ghostscript

I'm trying to access some Ghostscript functions like so:
[DllImport(#"C:\Program Files\GPLGS\gsdll32.dll", EntryPoint = "gsapi_revision")]
public static extern int Foo(gsapi_revision_t x, int len);
public struct gsapi_revision_t
{
[MarshalAs(UnmanagedType.LPTStr)]
string product;
[MarshalAs(UnmanagedType.LPTStr)]
string copyright;
long revision;
long revisiondate;
}
public static void Main()
{
gsapi_revision_t foo = new gsapi_revision_t();
Foo(foo, Marshal.SizeOf(foo));
This corresponds with these definitions from the iapi.h header from ghostscript:
typedef struct gsapi_revision_s {
const char *product;
const char *copyright;
long revision;
long revisiondate;
} gsapi_revision_t;
GSDLLEXPORT int GSDLLAPI
gsapi_revision(gsapi_revision_t *pr, int len);
But my code is reading nothing into the string fields. If I add 'ref' to the function, it reads gibberish. However, the following code reads in the data just fine:
public struct gsapi_revision_t
{
IntPtr product;
IntPtr copyright;
long revision;
long revisiondate;
}
public static void Main()
{
gsapi_revision_t foo = new gsapi_revision_t();
IntPtr x = Marshal.AllocHGlobal(20);
for (int i = 0; i < 20; i++)
Marshal.WriteInt32(x, i, 0);
int result = Foo(x, 20);
IntPtr productNamePtr = Marshal.ReadIntPtr(x);
IntPtr copyrightPtr = Marshal.ReadIntPtr(x, 4);
long revision = Marshal.ReadInt64(x, 8);
long revisionDate = Marshal.ReadInt64(x, 12);
byte[] dest = new byte[1000];
Marshal.Copy(productNamePtr, dest, 0, 1000);
string name = Read(productNamePtr);
string copyright = Read(copyrightPtr);
}
public static string Read(IntPtr p)
{
List<byte> bits = new List<byte>();
int i = 0;
while (true)
{
byte b = Marshal.ReadByte(new IntPtr(p.ToInt64() + i));
if (b == 0)
break;
bits.Add(b);
i++;
}
return Encoding.ASCII.GetString(bits.ToArray());
}
So what am I doing wrong with marshaling?
UnmanagedType.LPTStr is platform dependent (ANSI on Win98, Unicode on NT/XP). Your C++ structure uses the char * type, so you probably want UnmanagedType.LPStr instead.
Also, a long in C# is 64 bits while a long in C++ is 32 bits. You probably want to use int in your C# code.

Categories

Resources