急!!!C#调用C++方法传入ref的结构体参数问题!

时间:2022-08-30 19:09:00
C++的方法原型是这样的:

int Plat_GetAllCamera(int    iUserHandle,
        int    iNeedGetNum,
        PLAT_CAMERAINFO*  pCameraBuffer,
        int*   pOutputNum);

C++结构体是这样的:

 //监控点信息结构体
typedef  struct  _tagCameraInfo
{
    int iCameraID;    //监控点ID
    int iRegionID;    //所属区域ID
    int iControlCell; //所属中心ID
    int iDeviceID;    //设备ID
    int iDeviceChannel; //通道号
    char szCameraName[128];    //监控点名称
    int iStoreType[4]; //监控点录像位置数组 0代表无录像,1代表有录像

    //iStoreType[0]    //代表是否有设备录像;
    //iStoreType[1]    //代表是否有PCNVR录像;
    //iStoreType[2]    //代表是否有NVR录像;
    //iStoreType[3]    //代表是都有CVR录像。
    int iCameraState;       //监控点状态
}PLAT_CAMERAINFO,*LPPLAT_CAMERAINFO;

给出的调用示例是这样的:
 获取监控点资源(第一次调用获取资源数量,第二次调用获取详细信息)

//获取监控个数
if (-1 == Plat_GetAllCamera(g_iLoginHandle, 0,NULL, &PlatRtnCam))
{
   iErrNum = Plat_GetLastError(); 
}
NeedReadCam = PlatRtnCam;
pCameraInfo = new (std::nothrow) PLAT_CAMERAINFO[NeedReadCam];
if (NULL == pCameraInfo)
   break;
memset(pCameraInfo, 0, NeedReadCam * sizeof(PLAT_CAMERAINFO));
if (-1 == Plat_GetAllCamera(g_iLoginHandle, NeedReadCam, pCameraInfo, &PlatRtnCam))
{
   iErrNum = Plat_GetLastError(); 
}


C#的结构体定义:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct _tagCameraInfo
    {
        public Int32 iCameraID; //监控点ID
        public Int32 iRegionID; //所属区域ID
        public Int32 iControlCell; //所属中心ID
        public Int32 iDeviceID; //设备ID
        public Int32 iDeviceChannel; //通道号
        public byte[] szCameraName; //监控点名称
        public Int32[] iStoreType; ////监控点录像位置数组 0代表无录像,1代表有录像;iStoreType[0]代表是否有设备录像;iStoreType[1]代表是否有PCNVR录像;iStoreType[2]代表是否有NVR录像;iStoreType[3]代表是都有CVR录像。
        
        public Int32 iCameraState; //监控点状态
    }

C#的方法声明是这样的:

           [DllImport("PlatformSDK.dll", CharSet = CharSet.Ansi)]
        public unsafe static extern int Plat_GetAllCamera(int iUserHandle, int iNeedGetNum, ref _tagCameraInfo[] pCameraBuffer, ref int pOutputNum);

我的调用C#代码是这样的:
 

 int PlatRtnCam = 0;
            _tagCameraInfo[] pCameraInfo = null;
            if (-1 == Plat_GetAllCamera(g_iLoginHandle, 0, ref pCameraInfo, ref PlatRtnCam))
            {

            }
            pCameraInfo = new _tagCameraInfo[PlatRtnCam];
            for (int i = 0; i < pCameraInfo.Length; i++)
            {
                pCameraInfo[i].szCameraName = new byte[128];
                pCameraInfo[i].iStoreType = new int[4];
            }
            int CamCount = PlatRtnCam;
            if (-1 == Plat_GetAllCamera(g_iLoginHandle, CamCount, ref pCameraInfo, ref PlatRtnCam))
            {

            }

问题:第一次调用Plat_GetAllCamera的时候倒数第二个参数我这样传入null的时候,没有办法获取PlatRtnCam的真正值,所以后面就没有办法为传出参数pCameraInfo赋值了。求大家帮忙。真心谢谢了。

12 个解决方案

#1


纠正一下,因为info是数组,所以参数不用加ref,即便它是结构体

public unsafe static extern int Plat_GetAllCamera(int iUserHandle, int iNeedGetNum, _tagCameraInfo[] pCameraBuffer, ref int pOutputNum);  //声明
  
int n = Plat_GetAllCamera(10, 20,info, ref output); //调用

#2


pCameraInfo是结构体数组,所以传参的时候不能加ref

            int PlatRtnCam = 0;
            _tagCameraInfo[] pCameraInfo = null;
            if (-1 == Plat_GetAllCamera(g_iLoginHandle, 0, pCameraInfo, ref PlatRtnCam))
            {

            }
            pCameraInfo = new _tagCameraInfo[PlatRtnCam];
            for (int i = 0; i < pCameraInfo.Length; i++)
            {
                pCameraInfo[i].szCameraName = new byte[128];
                pCameraInfo[i].iStoreType = new int[4];
            }
            int CamCount = PlatRtnCam;
            if (-1 == Plat_GetAllCamera(g_iLoginHandle, CamCount, pCameraInfo, ref PlatRtnCam))
            {

            }

#3


引用 1 楼 sunny906 的回复:
纠正一下,因为info是数组,所以参数不用加ref,即便它是结构体

public unsafe static extern int Plat_GetAllCamera(int iUserHandle, int iNeedGetNum, _tagCameraInfo[] pCameraBuffer, ref int pOutputNum);  //声明
  
int n = Plat_GetAllCamera(10, 20,info, ref output); //调用

已经纠正,结果第二次调用出现内存问题

  int PlatRtnCam = 0;
            _tagCameraInfo[] pCameraInfo = null;
            if (-1 == Plat_GetAllCamera(g_iLoginHandle, 0, null, ref PlatRtnCam))
            {

            }
            pCameraInfo = new _tagCameraInfo[PlatRtnCam];
            for (int i = 0; i < pCameraInfo.Length; i++)
            {
                pCameraInfo[i].szCameraName = new byte[128];
                pCameraInfo[i].iStoreType = new int[4];
            }
            int CamCount = PlatRtnCam;
            if (-1 == Plat_GetAllCamera(g_iLoginHandle, CamCount, pCameraInfo, ref PlatRtnCam))
            {

            }

#4


看看我在你另一个帖子里的回复
http://bbs.csdn.net/topics/390853203

#5


引用 4 楼 sunny906 的回复:
看看我在你另一个帖子里的回复
http://bbs.csdn.net/topics/390853203

已经纠正那个ref了,现在抱:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。

        [DllImport("PlatformSDK.dll", CharSet = CharSet.Ansi)]
        public unsafe static extern int Plat_GetAllCamera(int iUserHandle, int iNeedGetNum, _tagCameraInfo[] pCameraBuffer, ref int pOutputNum);

#6


C#的结构体现在是这样的,不会报错了,可是,没有值出来,结构体这边会不会有问题?
  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct _tagCameraInfo
    {
        [MarshalAs(UnmanagedType.U4, SizeConst = 4)]
        public Int32 iCameraID; //监控点ID
        [MarshalAs(UnmanagedType.U4, SizeConst = 4)]
        public Int32 iRegionID; //所属区域ID
        [MarshalAs(UnmanagedType.U4, SizeConst = 4)]
        public Int32 iControlCell; //所属中心ID
        [MarshalAs(UnmanagedType.U4, SizeConst = 4)]
        public Int32 iDeviceID; //设备ID
        [MarshalAs(UnmanagedType.U4, SizeConst = 4)]
        public Int32 iDeviceChannel; //通道号
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
        public byte[] szCameraName; //监控点名称
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        public Int32[] iStoreType; ////监控点录像位置数组 0代表无录像,1代表有录像;iStoreType[0]代表是否有设备录像;iStoreType[1]代表是否有PCNVR录像;iStoreType[2]代表是否有NVR录像;iStoreType[3]代表是都有CVR录像。
        [MarshalAs(UnmanagedType.U4, SizeConst = 4)]
        public Int32 iCameraState; //监控点状态
    }

#7


你不用发两个帖子啊,在c++的代码里有一句memset(pCameraInfo, 0, NeedReadCam * sizeof(PLAT_CAMERAINFO));你得研究研究这句是起什么作用的,然后在C#里进行相应的改写

#8


引用 7 楼 sunny906 的回复:
你不用发两个帖子啊,在c++的代码里有一句memset(pCameraInfo, 0, NeedReadCam * sizeof(PLAT_CAMERAINFO));你得研究研究这句是起什么作用的,然后在C#里进行相应的改写

好的,上个帖子有的地方没有说清楚,没有办法修改。

#9


	class Program
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct PLAT_CAMERAINFO
{
public int iCameraID;
public int iRegionID;
public int iControlCell;
public int iDeviceID;
public int iDeviceChannel;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string szCameraName;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[] iStoreType;
public int iCameraState;
}

[DllImport("..\\..\\..\\Debug\\CForCS.dll")]
private static extern int Plat_GetAllCamera(int iUserHandle, int iNeedGetNum, [In, Out] PLAT_CAMERAINFO[] pCameraBuffer, out int pOutputNum);
static void Main(string[] args)
{
for (int i = 0; i < 3; ++i)
{
int count = 0;
Plat_GetAllCamera(i, 0, null, out count);
var array = new PLAT_CAMERAINFO[count];
Plat_GetAllCamera(i, count, array, out  count);
System.Diagnostics.Debug.WriteLine(string.Format("iUserHandle = {0}.", i));
System.Diagnostics.Debug.Indent();
foreach (var item in array)
{
System.Diagnostics.Debug.WriteLine(string.Format(".iCameraID = {0},", item.iCameraID));
System.Diagnostics.Debug.WriteLine(string.Format(".iRegionID = {0},", item.iRegionID));
System.Diagnostics.Debug.WriteLine(string.Format(".iControlCell = {0},", item.iControlCell));
System.Diagnostics.Debug.WriteLine(string.Format(".iDeviceID = {0},", item.iDeviceID));
System.Diagnostics.Debug.WriteLine(string.Format(".iDeviceChannel = {0},", item.iDeviceChannel));
System.Diagnostics.Debug.WriteLine(string.Format(".szCameraName = {0},", item.szCameraName));
System.Diagnostics.Debug.WriteLine(string.Format(".iStoreType = {0},", string.Join(",", item.iStoreType)));
System.Diagnostics.Debug.WriteLine(string.Format(".iCameraState = {0},", item.iCameraState));
}
System.Diagnostics.Debug.Unindent();
System.Diagnostics.Debug.WriteLine("");
}
}
}

#10


ref 不要乱用。

#11


观摩中...

#12


引用 10 楼 Saleayas 的回复:
ref 不要乱用。

谢谢你,照你的做法,可以了,学习了!非常感谢!

#1


纠正一下,因为info是数组,所以参数不用加ref,即便它是结构体

public unsafe static extern int Plat_GetAllCamera(int iUserHandle, int iNeedGetNum, _tagCameraInfo[] pCameraBuffer, ref int pOutputNum);  //声明
  
int n = Plat_GetAllCamera(10, 20,info, ref output); //调用

#2


pCameraInfo是结构体数组,所以传参的时候不能加ref

            int PlatRtnCam = 0;
            _tagCameraInfo[] pCameraInfo = null;
            if (-1 == Plat_GetAllCamera(g_iLoginHandle, 0, pCameraInfo, ref PlatRtnCam))
            {

            }
            pCameraInfo = new _tagCameraInfo[PlatRtnCam];
            for (int i = 0; i < pCameraInfo.Length; i++)
            {
                pCameraInfo[i].szCameraName = new byte[128];
                pCameraInfo[i].iStoreType = new int[4];
            }
            int CamCount = PlatRtnCam;
            if (-1 == Plat_GetAllCamera(g_iLoginHandle, CamCount, pCameraInfo, ref PlatRtnCam))
            {

            }

#3


引用 1 楼 sunny906 的回复:
纠正一下,因为info是数组,所以参数不用加ref,即便它是结构体

public unsafe static extern int Plat_GetAllCamera(int iUserHandle, int iNeedGetNum, _tagCameraInfo[] pCameraBuffer, ref int pOutputNum);  //声明
  
int n = Plat_GetAllCamera(10, 20,info, ref output); //调用

已经纠正,结果第二次调用出现内存问题

  int PlatRtnCam = 0;
            _tagCameraInfo[] pCameraInfo = null;
            if (-1 == Plat_GetAllCamera(g_iLoginHandle, 0, null, ref PlatRtnCam))
            {

            }
            pCameraInfo = new _tagCameraInfo[PlatRtnCam];
            for (int i = 0; i < pCameraInfo.Length; i++)
            {
                pCameraInfo[i].szCameraName = new byte[128];
                pCameraInfo[i].iStoreType = new int[4];
            }
            int CamCount = PlatRtnCam;
            if (-1 == Plat_GetAllCamera(g_iLoginHandle, CamCount, pCameraInfo, ref PlatRtnCam))
            {

            }

#4


看看我在你另一个帖子里的回复
http://bbs.csdn.net/topics/390853203

#5


引用 4 楼 sunny906 的回复:
看看我在你另一个帖子里的回复
http://bbs.csdn.net/topics/390853203

已经纠正那个ref了,现在抱:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。

        [DllImport("PlatformSDK.dll", CharSet = CharSet.Ansi)]
        public unsafe static extern int Plat_GetAllCamera(int iUserHandle, int iNeedGetNum, _tagCameraInfo[] pCameraBuffer, ref int pOutputNum);

#6


C#的结构体现在是这样的,不会报错了,可是,没有值出来,结构体这边会不会有问题?
  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct _tagCameraInfo
    {
        [MarshalAs(UnmanagedType.U4, SizeConst = 4)]
        public Int32 iCameraID; //监控点ID
        [MarshalAs(UnmanagedType.U4, SizeConst = 4)]
        public Int32 iRegionID; //所属区域ID
        [MarshalAs(UnmanagedType.U4, SizeConst = 4)]
        public Int32 iControlCell; //所属中心ID
        [MarshalAs(UnmanagedType.U4, SizeConst = 4)]
        public Int32 iDeviceID; //设备ID
        [MarshalAs(UnmanagedType.U4, SizeConst = 4)]
        public Int32 iDeviceChannel; //通道号
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
        public byte[] szCameraName; //监控点名称
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        public Int32[] iStoreType; ////监控点录像位置数组 0代表无录像,1代表有录像;iStoreType[0]代表是否有设备录像;iStoreType[1]代表是否有PCNVR录像;iStoreType[2]代表是否有NVR录像;iStoreType[3]代表是都有CVR录像。
        [MarshalAs(UnmanagedType.U4, SizeConst = 4)]
        public Int32 iCameraState; //监控点状态
    }

#7


你不用发两个帖子啊,在c++的代码里有一句memset(pCameraInfo, 0, NeedReadCam * sizeof(PLAT_CAMERAINFO));你得研究研究这句是起什么作用的,然后在C#里进行相应的改写

#8


引用 7 楼 sunny906 的回复:
你不用发两个帖子啊,在c++的代码里有一句memset(pCameraInfo, 0, NeedReadCam * sizeof(PLAT_CAMERAINFO));你得研究研究这句是起什么作用的,然后在C#里进行相应的改写

好的,上个帖子有的地方没有说清楚,没有办法修改。

#9


	class Program
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct PLAT_CAMERAINFO
{
public int iCameraID;
public int iRegionID;
public int iControlCell;
public int iDeviceID;
public int iDeviceChannel;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string szCameraName;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[] iStoreType;
public int iCameraState;
}

[DllImport("..\\..\\..\\Debug\\CForCS.dll")]
private static extern int Plat_GetAllCamera(int iUserHandle, int iNeedGetNum, [In, Out] PLAT_CAMERAINFO[] pCameraBuffer, out int pOutputNum);
static void Main(string[] args)
{
for (int i = 0; i < 3; ++i)
{
int count = 0;
Plat_GetAllCamera(i, 0, null, out count);
var array = new PLAT_CAMERAINFO[count];
Plat_GetAllCamera(i, count, array, out  count);
System.Diagnostics.Debug.WriteLine(string.Format("iUserHandle = {0}.", i));
System.Diagnostics.Debug.Indent();
foreach (var item in array)
{
System.Diagnostics.Debug.WriteLine(string.Format(".iCameraID = {0},", item.iCameraID));
System.Diagnostics.Debug.WriteLine(string.Format(".iRegionID = {0},", item.iRegionID));
System.Diagnostics.Debug.WriteLine(string.Format(".iControlCell = {0},", item.iControlCell));
System.Diagnostics.Debug.WriteLine(string.Format(".iDeviceID = {0},", item.iDeviceID));
System.Diagnostics.Debug.WriteLine(string.Format(".iDeviceChannel = {0},", item.iDeviceChannel));
System.Diagnostics.Debug.WriteLine(string.Format(".szCameraName = {0},", item.szCameraName));
System.Diagnostics.Debug.WriteLine(string.Format(".iStoreType = {0},", string.Join(",", item.iStoreType)));
System.Diagnostics.Debug.WriteLine(string.Format(".iCameraState = {0},", item.iCameraState));
}
System.Diagnostics.Debug.Unindent();
System.Diagnostics.Debug.WriteLine("");
}
}
}

#10


ref 不要乱用。

#11


观摩中...

#12


引用 10 楼 Saleayas 的回复:
ref 不要乱用。

谢谢你,照你的做法,可以了,学习了!非常感谢!