-
November 14th, 2013, 10:20 AM
#1
[RESOLVED] Wrapper from C++ to C#
Hi all,
I'm Marco and I'm a .NET software developer. I'm developing a C# console application based on a C++ set of DLLs using the DllImport attribute.
The C++ DLLs are part of a Video Management System SDK developed by a third part.
Following you'll find a piece of code that I wrote but that's not work properly:
Code:
[DllImport("TruVNetSDK.dll")]
public static extern int NET_DVR_Login_V30(string sDVRIP, int wDVRPort, string sUserName, string sPassword, out LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo);
public struct LPNET_DVR_DEVICEINFO_V30
{
public byte sSerialNumber;
public byte byAlarmInPortNum;
public byte byAlarmOutPortNum;
public byte byDiskNum;
public byte byChanNum;
public byte byStartChan; }
public void LogOn()
{
LPNET_DVR_DEVICEINFO_V30 _info;
NET_DVR_Login_V30("ip_address", port_number, "username", "password", out _info); }
And following the documentation provided by the third part developer team about the "NET_DVR_Login_V30" function and the "LPNET_DVR_DEVICEINFO_V30" struct:
LONG NET_DVR_Login_V30 (char *sDVRIP, WORD wDVRPort, char *sUserName, char *sPassword, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo)
Parameters:
sDVRIP
[in] IP address of the DVR
wServerPort
[in] Port NO. of the DVR
sUserName
[in] User's name
sPassword
[in] Password
lpDeviceInfo
[out] Information of device
struct{
BYTE sSerialNumber[SERIALNO_LEN];
BYTE byAlarmInPortNum;
BYTE byAlarmOutPortNum;
BYTE byDiskNum;
BYTE byChanNum;
BYTE byStartChan;
}NET_DVR_DEVICEINFO,*LPNET_DVR_DEVICEINFO;
Members:
sSerialNumber
Serial NO.
byAlarmInPortNum
The number of alarm input
byAlarmOutPortNum
The number of alarm output
byDiskNum
The number of hard disks
byChanNum
The number of analog channels
byStartChan
Start number of channel, start from 1 currently.
The problem is that I don't understand what kind of values are stored in the "_info" struct:
_info.sSerialNumber = 86
_info.byAlarmInPortNum = 82
_info.byAlarmOutPortNum = 48
_info.byDiskNum = 49
_info.byChanNum = 56
_info.byStartChan = 84
These values are not correct, the real values should be:
TVR11080820121218BBRR090016095WCVU
4
1
1
8
1
What's wrong?
Thank you a lot
-
November 14th, 2013, 12:07 PM
#2
Re: Wrapper from C++ to C#
You need to change your marshalling a bit.
Code:
public static extern int NET_DVR_Login_V30(string sDVRIP, int wDVRPort, string sUserName, string sPassword, out LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo);
public struct LPNET_DVR_DEVICEINFO_V30
{
public byte sSerialNumber;
public byte byAlarmInPortNum;
public byte byAlarmOutPortNum;
public byte byDiskNum;
public byte byChanNum;
public byte byStartChan;}
Should be something more like:
Code:
public static extern int NET_DVR_Login_V30([In][MarshalAs(UnmanagedType.LPWStr)] string sDVRIP, int wDVRPort, [In][MarshalAs(UnmanagedType.LPWStr)] string sUserName, [In][MarshalAs(UnmanagedType.LPWStr)] string sPassword, ref LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo);
public struct LPNET_DVR_DEVICEINFO_V30
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] // set to SERIALNO_LEN
public string sSerialNumber;
[MarshalAs(UnmanagedType.U1)]
public byte byAlarmInPortNum;
[MarshalAs(UnmanagedType.U1)]
public byte byAlarmOutPortNum;
[MarshalAs(UnmanagedType.U1)]
public byte byDiskNum;
[MarshalAs(UnmanagedType.U1)]
public byte byChanNum;
[MarshalAs(UnmanagedType.U1)]
public byte byStartChan;}
-
November 14th, 2013, 12:25 PM
#3
Re: Wrapper from C++ to C#
Great Tron it's working!
I think that I will study the MarshalAs attribute
-
November 18th, 2013, 11:06 AM
#4
Re: Wrapper from C++ to C#
Hi guys,
now I'm struggling to make work properly another function, following my piece of code:
Code:
[DllImport("TruVNetSDK.dll")]
public static extern bool NET_DVR_CaptureJPEGPicture(int lUserID, int lChannel, LPNET_DVR_JPEGPARA lpJpegPara, [In][MarshalAs(UnmanagedType.LPWStr)] string sPicFileName);
public struct LPNET_DVR_JPEGPARA
{
[MarshalAs(UnmanagedType.U2)]
public ushort wPicSize;
[MarshalAs(UnmanagedType.U2)]
public ushort wPicQuality; }
public bool CaptureJPEGPicture(int userId, int channelNumber)
{
LPNET_DVR_JPEGPARA param = new LPNET_DVR_JPEGPARA();
param.wPicSize = 0; // VGA
param.wPicQuality = 2; // best quality
return NET_DVR_CaptureJPEGPicture(userId, channelNumber, param, "D:\test.jpeg"); }
Following the SDK documentation:
BOOL NET_DVR_CaptureJPEGPicture(LONG lUserID, LONG lChannel, LPNET_DVR_JPEGPARA lpJpegPara, char *sPicFileName)
Parameters:
lUserID
[in] The return value of NET_DVR_Login_V30
lChannel
[in] Channel number
lpJpegPara
[in] JPEG image parameter
sPicFileName
[in] URL of JPEG file
Structure of JPEG picture parameters
struct{
WORD wPicSize;
WORD wPicQuality;
}NET_DVR_JPEGPARA,*LPNET_DVR_JPEGPARA;
Members
wPicSize
Size of picture: 0-CIF, 1-QCIF, 2-D1, 3-UXGA, 4-SVGA, 5-HD720p, 6-VGA, 7-XVGA, 8-HD900p, 9-HD1080, 10-2560*1920, 11-1600*304, 12-2048*1536, 13-2448*2048
wPicQuality
Picture quality: 0- best, 1- better, 2- average
When I call CaptureJPEGPicture() an exception is thrown:
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Why this error?
Thank you a lot!
Marco
-
November 18th, 2013, 11:55 AM
#5
Re: Wrapper from C++ to C#
The first method works because you are receiving the structure from the API so a pointer will do the trick.
To send structures to the API you'll have to do more.
Something like this:
Code:
IntPtr pStruct = Marshal.AllocCoTaskMem(structureSize);
if (null != pStruct )
{
Marshal.Copy(myStruct, 0, pStruct , structureSize);
// use pStruct
Marshal.FreeCoTaskMem(pStruct);
}
-
November 18th, 2013, 01:20 PM
#6
Re: Wrapper from C++ to C#
Actually in your case you most likely need the following line instead of Marshal.Copy().
Code:
Marshal.StructureToPtr(myStruct, pStruct, false)
-
November 19th, 2013, 01:35 PM
#7
Re: Wrapper from C++ to C#
Originally Posted by Tron
Actually in your case you most likely need the following line instead of Marshal.Copy().
Code:
Marshal.StructureToPtr(myStruct, pStruct, false)
Thank you!!! It works.
I have another question. The documentation says:
BOOL NET_DVR_GetDVRConfig(LONG lUserID, DWORD dwCommand, LONG lChannel, LPVOID lpOutBuffer, DWORD dwOutBufferSize, LPDWORD lpBytesReturned)
Parameters:
lUserID
[in] The return value of NET_DVR_Login_V30
dwCommand
[in] Configuration command, please kindly refer to the DwCommand type definition below
lChannel
[in] Channel number. If the channel parameter is not required, lChannel is invalid, and set it as 0xFFFFFFFF.
lpOutBuffer
[out] The buffer to save the received data
dwOutBufferSize
[in] The size of the buffer (unit: byte). It can't be 0.
lpBytesReturned
[out] The size of the returned buffer, it can't be NULL
Return value: Returns TRUE on success, FALSE on failure. Please call NET_DVR_GetLastError to get the error code.
The lpOutBuffer must be a struct like the following:
Structure of channel video configuration (NET_DVR_PICCFG_V30)
struct{
DWORD dwSize;
BYTE sChanName[NAME_LEN];
DWORD dwVideoFormat;
char reservedData[64];
DWORD dwShowChanName;
WORD wShowNameTopLeftX;
WORD wShowNameTopLeftY;
NET_DVR_VILOST_V30 struVILost;
NET_DVR_VILOST_V30 struRes;
NET_DVR_MOTION_V30 struMotion;
NET_DVR_HIDEALARM_V30 struHideAlarm;
DWORD dwEnableHide;
NET_DVR_SHELTER struShelter[MAX_SHELTERNUM];
DWORD dwShowOsd;
WORD wOSDTopLeftX;
WORD wOSDTopLeftY;
BYTE byOSDType;
BYTE byDispWeek;
BYTE byOSDAttrib;
BYTE byHourOsdType;
BYTE byRes[63];
BYTE byCovert; }NET_DVR_PICCFG_V30,*LPNET_DVR_PICCFG_V30;
Members:
dwSize
Size of structure
sChanName
Channel name
dwVideoFormat
Video format: 1-NTSC, 2-PAL
reservedData
Reserved, set to 0
dwShowChanName
Whether display channel name on previewing image: 0- don't display, 1- display(size of area: 704*576)
wShowNameTopLeftX
X axis coordinate of channel name displaying location
wShowNameTopLeftY
Y axis coordinate of channel name displaying location
struVILost
Video lost alarm parameter
struRes
Reserved, set to 0
struMotion
Motion detection alarm parameter
struHideAlarm
Video tampering alarm parameter
dwEnableHide
Enable tempering or not: 0- no, 1- yes
struShelter
Parameters of tampering area
dwShowOsd
Whether to display OSD on preview image: 0- don't display, 1- display(size of area: 704*576)
wOSDTopLeftX
X axis coordinate of OSD
wOSDTopLeftY
Y axis coordinate of OSD
byOSDType
OSD type (year month day format):
0-XXXX-XX-XX year-month-day
1-XX-XX-XXXX month-day-year
2-XXXX(year)XX(month)XX(day)
3-XX(month)XX(day)XXXX(year)
4-XX-XX-XXXX day-month-year
5-XX(day)XX(month)XXXX(year)
byDispWeek
Whethet to display week: 0- don't display, 1- display
byOSDAttrib
OSD attribute (transparent or flash):
1- transparent and flash
2- transparent, non- flash
3- flash, non-transparent
4- non-transparent, non-flash
byHourOsdType
Hour display format: 0 means 24-hour format, 1 means 12-hour format or am/pm format
byRes
Reserved, set to 0
byCovert
Covert the channel 0-not covert,1-covert,only super user can set
My code for the DllImport and for the struct is the following:
Code:
[DllImport("TruVNetSDK.dll")]
public static extern bool NET_DVR_GetDVRConfig(int lUserID, uint dwCommand, int lChannel, IntPtr lpOutBuffer, uint dwOutBufferSize, ref uint lpBytesReturned);
public struct NET_DVR_PICCFG_V30
{
public int dwSize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] sChanName;
public int dwVideoFormat;
//public NET_DVR_VICOLOR struViColor;
public int dwShowChanName;
public short wShowNameTopLeftX;
public short wShowNameTopLeftY;
//public NET_DVR_VILOST_V30 struVILost;
//public NET_DVR_VILOST_V30 struAULost;
//public NET_DVR_MOTION_V30 struMotion;
//public NET_DVR_HIDEALARM_V30 struHideAlarm;
public int dwEnableHide;
//public NET_DVR_SHELTER[] struShelter = new NET_DVR_SHELTER[4];
public int dwShowOsd;
public short wOSDTopLeftX;
public short wOSDTopLeftY;
public byte byOSDType;
public byte byDispWeek;
public byte byOSDAttrib;
public byte byHourOSDType;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public byte[] byRes;
}
And then the call:
Code:
Wrapper.NET_DVR_PICCFG_V30 _struct = new Wrapper.NET_DVR_PICCFG_V30();
Int32 nSize = Marshal.SizeOf(_struct);
IntPtr ptrPICOutCfg = Marshal.AllocHGlobal(nSize);
Marshal.StructureToPtr(_struct, ptrPICOutCfg, false);
UInt32 dwReturn = 0;
bool bRet = false;
bRet = Wrapper.TruVNetSDK.NET_DVR_GetDVRConfig(0, (uint)1002, 1, ptrPICOutCfg, (UInt32)nSize, ref dwReturn);
But the bRet is always FALSE
I've commented some rows in the structs because I don't need these values, it's wrong?
Thank you as usual!!!
Marco
-
November 19th, 2013, 02:10 PM
#8
Re: Wrapper from C++ to C#
I think you may want to change this:
Code:
[DllImport("TruVNetSDK.dll")]
public static extern bool NET_DVR_GetDVRConfig(int lUserID, uint dwCommand, int lChannel, IntPtr lpOutBuffer, uint dwOutBufferSize, ref uint lpBytesReturned);
To:
Code:
[DllImport("TruVNetSDK.dll")]
public static extern bool NET_DVR_GetDVRConfig(int lUserID, uint dwCommand, int lChannel, ref NET_DVR_PICCFG_V30 lpStruct, uint dwOutBufferSize, ref uint lpBytesReturned);
Not sure if that will work but I think it might.
What you have for marshalling your structure may have worked but you can make it simplier I think if the above PInvoke works.
Code:
Wrapper.NET_DVR_PICCFG_V30 _struct = new Wrapper.NET_DVR_PICCFG_V30();
UInt32 dwReturn = 0;
bool bRet = false;
bRet = Wrapper.TruVNetSDK.NET_DVR_GetDVRConfig(0, (uint)1002, 1, ref _struct, (UInt32)nSize, ref dwReturn);
That said, unfortunately are going to have to define every member of that API structure in your wrapper. You can't skip over any of them because that will drastically change the overall size of the structure.
Oh on a side note you may want to pair these two calls together when doing your StructureToPtr().
Code:
Marshal.StructureToPtr(myStruct, pStruct, false)
// use pStruct
Marshal.DestroyStructure(pStruct, typeof(myStructType));
Last edited by Tron; November 19th, 2013 at 02:13 PM.
-
November 19th, 2013, 02:20 PM
#9
Re: Wrapper from C++ to C#
Depending on the members of NET_DVR_VICOLOR, NET_DVR_VILOST_V30 and NET_DVR_HIDEALARM_V30 this line of the structure may be the most tricky.
Code:
public NET_DVR_SHELTER[] struShelter = new NET_DVR_SHELTER[4];
So probably define the other structures first to see if they may have other potential areas of concern then come back to the array of NET_DVR_SHELTER structures.
This array may be a non-issue if the pointers can be set to NULL since you are not using the structures.
Last edited by Tron; November 19th, 2013 at 02:22 PM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|