[RESOLVED] Wrapper from C++ to C#
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 9 of 9

Thread: [RESOLVED] Wrapper from C++ to C#

  1. #1
    Join Date
    Nov 2013
    Location
    Milan [.NET 4.5]
    Posts
    17

    [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

  2. #2
    Join Date
    May 2002
    Posts
    487

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

  3. #3
    Join Date
    Nov 2013
    Location
    Milan [.NET 4.5]
    Posts
    17

    Re: Wrapper from C++ to C#

    Great Tron it's working!

    I think that I will study the MarshalAs attribute

  4. #4
    Join Date
    Nov 2013
    Location
    Milan [.NET 4.5]
    Posts
    17

    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

  5. #5
    Join Date
    May 2002
    Posts
    487

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

  6. #6
    Join Date
    May 2002
    Posts
    487

    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)

  7. #7
    Join Date
    Nov 2013
    Location
    Milan [.NET 4.5]
    Posts
    17

    Re: Wrapper from C++ to C#

    Quote Originally Posted by Tron View Post
    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

  8. #8
    Join Date
    May 2002
    Posts
    487

    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 01:13 PM.

  9. #9
    Join Date
    May 2002
    Posts
    487

    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 01: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
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center