C#中调用c++dll的结构体传递问题

时间:2022-08-30 19:56:06
c++中发的原型是这样的:
typedef struct ucvACF
{
float *ucvTemp;
float *ucvGx;
float *ucvGy;
float *angles;
int *ucvGray;

float *hist[6];
float *channels[10];
int *acf_channels[10];

int mW,mH,dimensions;
float *mLUV;
float *ucvGradMag;
}
在C#中将其对应成了如下形式:
 public struct ucvACF
        {
            public int mW;
            public int mH;
            public int dimensions;
            public IntPtr mLUV;          
            public IntPtr ucvGradMag;         
            public IntPtr ucvTemp;          
            public IntPtr ucvGx;            
            public IntPtr ucvGy;          
            public IntPtr angles;           
            public IntPtr ucvGray;
            //[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
            public IntPtr hist;
            //[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
            public IntPtr channels;
           // [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
            public IntPtr acf_channels;
}
然后通过 Marshal.StructureToPtr(myucvACF, ptr1, true) 将结构体传到了函数内部,可是运行结果不正确,追踪到dll内部发现dll内的数据是正确的,可是通过System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes)将mLUV中的数据考到luv中时,数据是错误的,请问各位大神是怎么回事????

29 个解决方案

#1



[StructLayout(LayoutKind.Sequential)]  
public struct ucvACF
{
public IntPtr ucvTemp;
public IntPtr ucvGx;
public IntPtr ucvGy;
public IntPtr angles;
public IntPtr ucvGray;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public IntPtr[] hist;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public IntPtr[] channels;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public IntPtr[] acf_channels;

public int mW;
public int mH;
public int dimensions;
public IntPtr mLUV;
public IntPtr ucvGradMag;
}


你这c++原型是哪家孩子写的,如果是专门写来和c#交互的,那写的真是够了,否则就罢了

#2


你写的结构体和c++里完全不同,至少顺序要一样,结构体要加上[StructLayout(LayoutKind.Sequential)] 

#3


建议换成System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, floats)

#4


引用 1 楼 lc316546079 的回复:

[StructLayout(LayoutKind.Sequential)]  
public struct ucvACF
{
public IntPtr ucvTemp;
public IntPtr ucvGx;
public IntPtr ucvGy;
public IntPtr angles;
public IntPtr ucvGray;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public IntPtr[] hist;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public IntPtr[] channels;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public IntPtr[] acf_channels;

public int mW;
public int mH;
public int dimensions;
public IntPtr mLUV;
public IntPtr ucvGradMag;
}


你这c++原型是哪家孩子写的,如果是专门写来和c#交互的,那写的真是够了,否则就罢了


本来那么写 追踪到dll里的数据还是对的,结构改成这种形式后dll中结构体内的数据都不对

#5


本来会对,才奇怪了,
发代码吧

#6


引用 5 楼 lc316546079 的回复:
本来会对,才奇怪了,
发代码吧


         private unsafe void luv_Click(object sender, EventArgs e)
        {
            if (curBitmap != null)
            {
                myTimer.ClearTimer();
                myTimer.Start();

                Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);//获得感兴趣区,前边是坐标,后边是大小
                System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);//锁定感兴趣区,只能在此区域操作(第二个参数指明可以进行何种操作)
                IntPtr ptr = bmpData.Scan0;//获取第一行地址
                ucvACF myucvACF = new ucvACF();
                myucvACF.mW = curBitmap.Width;
                myucvACF.mH = curBitmap.Height;
                myucvACF.dimensions = 3;
                //将结构体转换为指针
                int size = Marshal.SizeOf(myucvACF);
                byte[] buf = new byte[size];
                IntPtr ptr1 = Marshal.AllocHGlobal(size);//分配结构体大小的空间
                Marshal.StructureToPtr(myucvACF, ptr1, true);//将结构体拷到分配好的内存空间  
            MallocChannels(ptr1);//dll中函数,主要在分配内存
            for(int i=0;i<10;i++){
                    FeatureCompute(ptr1, ptr);//dll中函数,进行图像的一些处理
            }
                //指针转回结构体
                ucvACF myucvACF1;
                myucvACF1 = (ucvACF)Marshal.PtrToStructure(ptr1, typeof(ucvACF));
                //定义一个数组保存图片
                int bytes = curBitmap.Width * curBitmap.Height * 3;
                byte[] luv = new byte[bytes];
                System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);//复制RGB的值到所声明的数组中
                System.Runtime.InteropServices.Marshal.Copy(luv, 0, ptr, bytes);
                curBitmap.UnlockBits(bmpData);
                myTimer.Stop();
                timeBox.Text = myTimer.Duration.ToString("####.##") + " 毫秒";
                Invalidate();               
            }
        }

#7


你这里获得的size是多少
int size = Marshal.SizeOf(myucvACF);

dll中 sizeof(ucvACF)获得的大小又是多少;
-----------------------
既然你说你追踪到了dll里的数据,说明你有dll的源码,建议把这个结构体改了,弄那么多指针干什么,c#操作起来那么麻烦

#8


引用 7 楼 lc316546079 的回复:
你这里获得的size是多少
int size = Marshal.SizeOf(myucvACF);

dll中 sizeof(ucvACF)获得的大小又是多少;
-----------------------
既然你说你追踪到了dll里的数据,说明你有dll的源码,建议把这个结构体改了,弄那么多指针干什么,c#操作起来那么麻烦


dll中不用计算这个的大小,直接传结构体指针就行了,不过我用C在外面定义了一个一样的结构体试了一下,两个大小还真不一样。代码是师兄给的,只说让我用C#搭界面,如果把那个结构体改了,得改好多地方

#9


如果你师兄不能给封装个c#的接口,并且测试通过,那么你就换一个项目吧。

#10


c++中的指针,意味着可能“胡写乱写,并没有确定的最终含义。

既然是可以协作的,那么凡是这种接口应该让底层的c++程序员去写,并且调试通过。或者让c#程序原来按照自己的要求制定接口规范,然后c++程序去实现。

#11


引用 8 楼 tianxiaoying22 的回复:
dll中不用计算这个的大小,直接传结构体指针就行了,不过我用C在外面定义了一个一样的结构体试了一下,两个大小还真不一样。代码是师兄给的,只说让我用C#搭界面,方


从你贴出的两段代码可以看出来,你连 顺序都不一样,说明你不是从c++那种比较低级的面向字节顺序的角度去理解c++,而是从c#的高级的面向类型的角度去理解c++。你现在还没有理解c和c++语言啊。

#12





引用 11 楼 sp1234 的回复:
Quote: 引用 8 楼 tianxiaoying22 的回复:

dll中不用计算这个的大小,直接传结构体指针就行了,不过我用C在外面定义了一个一样的结构体试了一下,两个大小还真不一样。代码是师兄给的,只说让我用C#搭界面,方


从你贴出的两段代码可以看出来,你连 顺序都不一样,说明你不是从c++那种比较低级的面向字节顺序的角度去理解c++,而是从c#的高级的面向类型的角度去理解c++。你现在还没有理解c和c++语言啊。


额 我大学学的不是计算机,只在大一简单的学过几天C, 所以.........

#13


要改很多东西?
且不谈那么多指针,就算在c/c++中管理内存会稍显麻烦;
就c#的使用来说全是intptr每次的get要 ptr to struct,每次set要struct to ptr.........累。。。
还有那数组。。。。c#的数组在堆里结构体只保留指针,c/c++那数组是实际存放在结构体里。。。
c++提供给c#的接口,最好要c# c/c++都了解的人来封装更合适,里面更多的是c#的认识,我的建议是由一个 真正 熟悉c#且了解c/c++的人来定义及封装;如果没有,那就让你自己做那个人。。。

另外我提议你获取两边的size意思是让你明白两边结构体并不对应,根据差多少字节,去思考了解c# c/c++关于结构体在内存中的存放原理。

#14


C#中全用指针即可,取值也用指针,操作方便简单,目前我还没遇到过不能成功的结构体

#15


引用 14 楼 bigbaldy 的回复:
C#中全用指针即可,取值也用指针,操作方便简单,目前我还没遇到过不能成功的结构体


什么叫取值也用指针,我昨天代码贴错了,结构体顺序是一致的,穿进去了,dll里的数据也正确,所以我觉得应该在向外拷数据的时候出的错,我是通过下面的方法将mluv里的数据考到图片中的
int bytes = curBitmap.Width * curBitmap.Height * 3;
byte[] luv = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);
System.Runtime.InteropServices.Marshal.Copy(luv, 0, ptr, bytes);//其中ptr是Tntptr类型,指向图片首地址
如果用C/C++的话是这样操作的
for (int i = 0; i < height; i++)
{
for (int j = 0; j < widthStep; j += step)
{
im.data[i*widthStep+j] = (unsigned char)UucvACF->mluv[i*widthStep+j];
im.data[i*widthStep+j+1] = (unsigned char)UucvACF->mluv[i*widthStep+j+1];
im.data[i*widthStep+j+2] = (unsigned char)UucvACF->mluv[i*widthStep+j+2];
}
}
结果是C#中的luv里的数据和C中im.data[]里的数据不一样,我在想是不是copy()出了错,或者是类型对应有错误
谢谢各位了

#16


这得按顺序啊,封送过程其实就是内存数据传递

所以,你内存顺序不同,结果自然不可知。话说你这样乱串居然没木溢出也算是个小奇迹了

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct ucvACF {
    
    /// float*
    public System.IntPtr ucvTemp;
    
    /// float*
    public System.IntPtr ucvGx;
    
    /// float*
    public System.IntPtr ucvGy;
    
    /// float*
    public System.IntPtr angles;
    
    /// int*
    public System.IntPtr ucvGray;
    
    /// float*[6]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=6, ArraySubType=System.Runtime.InteropServices.UnmanagedType.SysUInt)]
    public System.IntPtr[] hist;
    
    /// float*[10]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=10, ArraySubType=System.Runtime.InteropServices.UnmanagedType.SysUInt)]
    public System.IntPtr[] channels;
    
    /// int*[10]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=10, ArraySubType=System.Runtime.InteropServices.UnmanagedType.SysUInt)]
    public System.IntPtr[] acf_channels;
    
    /// int
    public int mW;
    
    /// int
    public int mH;
    
    /// int
    public int dimensions;
    
    /// float*
    public System.IntPtr mLUV;
    
    /// float*
    public System.IntPtr ucvGradMag;
}


#17


不好意思各位,我C的代码贴错了,顺序一样,
typedef struct ucvACF
{
int mW,mH,dimensions;
float *mLUV;
float *ucvGradMag;
        float *ucvTemp;
float *ucvGx;
float *ucvGy;
float *angles;
int *ucvGray;

float *hist[6];
float *channels[10];
int *acf_channels[10];
}

#18


引用 16 楼 wanghui0380 的回复:
这得按顺序啊,封送过程其实就是内存数据传递

所以,你内存顺序不同,结果自然不可知。话说你这样乱串居然没木溢出也算是个小奇迹了

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct ucvACF {
    
    /// float*
    public System.IntPtr ucvTemp;
    
    /// float*
    public System.IntPtr ucvGx;
    
    /// float*
    public System.IntPtr ucvGy;
    
    /// float*
    public System.IntPtr angles;
    
    /// int*
    public System.IntPtr ucvGray;
    
    /// float*[6]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=6, ArraySubType=System.Runtime.InteropServices.UnmanagedType.SysUInt)]
    public System.IntPtr[] hist;
    
    /// float*[10]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=10, ArraySubType=System.Runtime.InteropServices.UnmanagedType.SysUInt)]
    public System.IntPtr[] channels;
    
    /// int*[10]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=10, ArraySubType=System.Runtime.InteropServices.UnmanagedType.SysUInt)]
    public System.IntPtr[] acf_channels;
    
    /// int
    public int mW;
    
    /// int
    public int mH;
    
    /// int
    public int dimensions;
    
    /// float*
    public System.IntPtr mLUV;
    
    /// float*
    public System.IntPtr ucvGradMag;
}


不好意思我代码贴错了,现在的问题是这个:
我追到dll里边,发现dll里的数据正确,所以我觉得应该在向外拷数据的时候出的错,我是通过下面的方法将mluv里的数据考到图片中的
int bytes = curBitmap.Width * curBitmap.Height * 3;
byte[] luv = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);
System.Runtime.InteropServices.Marshal.Copy(luv, 0, ptr, bytes);//其中ptr是Tntptr类型,指向图片首地址
如果用C/C++的话是这样操作的
for (int i = 0; i < height; i++)
{
for (int j = 0; j < widthStep; j += step)
{
im.data[i*widthStep+j] = (unsigned char)UucvACF->mluv[i*widthStep+j];
im.data[i*widthStep+j+1] = (unsigned char)UucvACF->mluv[i*widthStep+j+1];
im.data[i*widthStep+j+2] = (unsigned char)UucvACF->mluv[i*widthStep+j+2];
}
}
结果是C#中的luv里的数据和C中im.data[]里的数据不一样,我在想是不是copy()出了错,或者是类型对应有错误

#19


引用 10 楼 sp1234 的回复:
c++中的指针,意味着可能“胡写乱写,并没有确定的最终含义。

既然是可以协作的,那么凡是这种接口应该让底层的c++程序员去写,并且调试通过。或者让c#程序原来按照自己的要求制定接口规范,然后c++程序去实现。


大家没有人懂C#。。。。。都是用C/C++
我昨天代码贴错了,两个结构体顺序一致,现在问题是这样的,我追到dll里边,发现dll里的数据正确,所以我觉得应该在向外拷数据的时候出的错,我是通过下面的方法将mluv里的数据考到图片中的
int bytes = curBitmap.Width * curBitmap.Height * 3;
byte[] luv = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);
System.Runtime.InteropServices.Marshal.Copy(luv, 0, ptr, bytes);//其中ptr是Tntptr类型,指向图片首地址
如果用C/C++的话是这样操作的
for (int i = 0; i < height; i++)
{
for (int j = 0; j < widthStep; j += step)
{
im.data[i*widthStep+j] = (unsigned char)UucvACF->mluv[i*widthStep+j];
im.data[i*widthStep+j+1] = (unsigned char)UucvACF->mluv[i*widthStep+j+1];
im.data[i*widthStep+j+2] = (unsigned char)UucvACF->mluv[i*widthStep+j+2];
}
}
结果是C#中的luv里的数据和C中im.data[]里的数据不一样,我在想是不是copy()出了错,或者是类型对应有错误

您觉得是什么原因呢

#20


有关你最后一个问题,inptr只是一个指针,按照你的东西,我觉着你可以使用BitmapData去接收

#21


BitmapData 设置好宽高,范围后。直接把Scan0 的指针指向到你获取到的那个intptr上看看

#22


如果c++ 那段代码里 widthStep 是 width *3 且 step 是3的话,那你这样copy就不该有错;
你可以先在dll中看mLUV指向的地址是多少,再在c#中看是多少,对比是否一致;
如果一致,再拿copy以后bytes里的数据,和dll中mLUV数据做对比看怎么个不一样法

#23


引用 22 楼 lc316546079 的回复:
如果c++ 那段代码里 widthStep 是 width *3 且 step 是3的话,那你这样copy就不该有错;
你可以先在dll中看mLUV指向的地址是多少,再在c#中看是多少,对比是否一致;
如果一致,再拿copy以后bytes里的数据,和dll中mLUV数据做对比看怎么个不一样法


两个地址一样,但是两个数据完全不一样,dll中mluv的数据是正确的,bytes里不对

#24


引用 22 楼 lc316546079 的回复:
如果c++ 那段代码里 widthStep 是 width *3 且 step 是3的话,那你这样copy就不该有错;
你可以先在dll中看mLUV指向的地址是多少,再在c#中看是多少,对比是否一致;
如果一致,再拿copy以后bytes里的数据,和dll中mLUV数据做对比看怎么个不一样法


dll中mluv的前五个数分别为,70 29 84 70 29;bytes中为11 219 141 66 8。这有什么规律在里边吗,我实在看不出来。

#25


引用 21 楼 wanghui0380 的回复:
BitmapData 设置好宽高,范围后。直接把Scan0 的指针指向到你获取到的那个intptr上看看


我的ptr本来是指向原图的Scan0,现在我ptr = myucvACF1.mLUV,结果输出原图,没有变;;可是我用上边的方法,结果是雪花,这是什么原因

#26


引用 24 楼 tianxiaoying22 的回复:
Quote: 引用 22 楼 lc316546079 的回复:

如果c++ 那段代码里 widthStep 是 width *3 且 step 是3的话,那你这样copy就不该有错;
你可以先在dll中看mLUV指向的地址是多少,再在c#中看是多少,对比是否一致;
如果一致,再拿copy以后bytes里的数据,和dll中mLUV数据做对比看怎么个不一样法


dll中mluv的前五个数分别为,70 29 84 70 29;bytes中为11 219 141 66 8。这有什么规律在里边吗,我实在看不出来。

一步一步找错,既然你说dll 里看到的 mLUVd地址和c#里看到的一样,那就比数据,
在System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);断点
查看myucvACF1.mLUV地址,复制, 去菜单的 调试->窗口->内存 里查看该地址的数据,和dll中时 mLUV是否一致;
在地址一致时,数据肯定也是一致的,如果不对,只能是你哪里细节说错了,且你自认为没错

#27


引用 26 楼 lc316546079 的回复:
Quote: 引用 24 楼 tianxiaoying22 的回复:

Quote: 引用 22 楼 lc316546079 的回复:

如果c++ 那段代码里 widthStep 是 width *3 且 step 是3的话,那你这样copy就不该有错;
你可以先在dll中看mLUV指向的地址是多少,再在c#中看是多少,对比是否一致;
如果一致,再拿copy以后bytes里的数据,和dll中mLUV数据做对比看怎么个不一样法


dll中mluv的前五个数分别为,70 29 84 70 29;bytes中为11 219 141 66 8。这有什么规律在里边吗,我实在看不出来。

一步一步找错,既然你说dll 里看到的 mLUVd地址和c#里看到的一样,那就比数据,
在System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);断点
查看myucvACF1.mLUV地址,复制, 去菜单的 调试->窗口->内存 里查看该地址的数据,和dll中时 mLUV是否一致;
在地址一致时,数据肯定也是一致的,如果不对,只能是你哪里细节说错了,且你自认为没错


C#可以看内存吗?我怎么看不了,查了一下好像说不让看

#28


C#中调用c++dll的结构体传递问题

#29


引用 27 楼 tianxiaoying22 的回复:
Quote: 引用 26 楼 lc316546079 的回复:

Quote: 引用 24 楼 tianxiaoying22 的回复:

Quote: 引用 22 楼 lc316546079 的回复:

如果c++ 那段代码里 widthStep 是 width *3 且 step 是3的话,那你这样copy就不该有错;
你可以先在dll中看mLUV指向的地址是多少,再在c#中看是多少,对比是否一致;
如果一致,再拿copy以后bytes里的数据,和dll中mLUV数据做对比看怎么个不一样法


dll中mluv的前五个数分别为,70 29 84 70 29;bytes中为11 219 141 66 8。这有什么规律在里边吗,我实在看不出来。

一步一步找错,既然你说dll 里看到的 mLUVd地址和c#里看到的一样,那就比数据,
在System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);断点
查看myucvACF1.mLUV地址,复制, 去菜单的 调试->窗口->内存 里查看该地址的数据,和dll中时 mLUV是否一致;
在地址一致时,数据肯定也是一致的,如果不对,只能是你哪里细节说错了,且你自认为没错


C#可以看内存吗?我怎么看不了,查了一下好像说不让看


。。。。谁说不让看。。。我在mac下没有vs不能截图,但是“菜单 调试->窗口->内存”这样打开的调试窗口是可以看内存的,大概菜单式这么点,没vs在手上我也不确定你去菜单里找找

#1



[StructLayout(LayoutKind.Sequential)]  
public struct ucvACF
{
public IntPtr ucvTemp;
public IntPtr ucvGx;
public IntPtr ucvGy;
public IntPtr angles;
public IntPtr ucvGray;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public IntPtr[] hist;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public IntPtr[] channels;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public IntPtr[] acf_channels;

public int mW;
public int mH;
public int dimensions;
public IntPtr mLUV;
public IntPtr ucvGradMag;
}


你这c++原型是哪家孩子写的,如果是专门写来和c#交互的,那写的真是够了,否则就罢了

#2


你写的结构体和c++里完全不同,至少顺序要一样,结构体要加上[StructLayout(LayoutKind.Sequential)] 

#3


建议换成System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, floats)

#4


引用 1 楼 lc316546079 的回复:

[StructLayout(LayoutKind.Sequential)]  
public struct ucvACF
{
public IntPtr ucvTemp;
public IntPtr ucvGx;
public IntPtr ucvGy;
public IntPtr angles;
public IntPtr ucvGray;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public IntPtr[] hist;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public IntPtr[] channels;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public IntPtr[] acf_channels;

public int mW;
public int mH;
public int dimensions;
public IntPtr mLUV;
public IntPtr ucvGradMag;
}


你这c++原型是哪家孩子写的,如果是专门写来和c#交互的,那写的真是够了,否则就罢了


本来那么写 追踪到dll里的数据还是对的,结构改成这种形式后dll中结构体内的数据都不对

#5


本来会对,才奇怪了,
发代码吧

#6


引用 5 楼 lc316546079 的回复:
本来会对,才奇怪了,
发代码吧


         private unsafe void luv_Click(object sender, EventArgs e)
        {
            if (curBitmap != null)
            {
                myTimer.ClearTimer();
                myTimer.Start();

                Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);//获得感兴趣区,前边是坐标,后边是大小
                System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);//锁定感兴趣区,只能在此区域操作(第二个参数指明可以进行何种操作)
                IntPtr ptr = bmpData.Scan0;//获取第一行地址
                ucvACF myucvACF = new ucvACF();
                myucvACF.mW = curBitmap.Width;
                myucvACF.mH = curBitmap.Height;
                myucvACF.dimensions = 3;
                //将结构体转换为指针
                int size = Marshal.SizeOf(myucvACF);
                byte[] buf = new byte[size];
                IntPtr ptr1 = Marshal.AllocHGlobal(size);//分配结构体大小的空间
                Marshal.StructureToPtr(myucvACF, ptr1, true);//将结构体拷到分配好的内存空间  
            MallocChannels(ptr1);//dll中函数,主要在分配内存
            for(int i=0;i<10;i++){
                    FeatureCompute(ptr1, ptr);//dll中函数,进行图像的一些处理
            }
                //指针转回结构体
                ucvACF myucvACF1;
                myucvACF1 = (ucvACF)Marshal.PtrToStructure(ptr1, typeof(ucvACF));
                //定义一个数组保存图片
                int bytes = curBitmap.Width * curBitmap.Height * 3;
                byte[] luv = new byte[bytes];
                System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);//复制RGB的值到所声明的数组中
                System.Runtime.InteropServices.Marshal.Copy(luv, 0, ptr, bytes);
                curBitmap.UnlockBits(bmpData);
                myTimer.Stop();
                timeBox.Text = myTimer.Duration.ToString("####.##") + " 毫秒";
                Invalidate();               
            }
        }

#7


你这里获得的size是多少
int size = Marshal.SizeOf(myucvACF);

dll中 sizeof(ucvACF)获得的大小又是多少;
-----------------------
既然你说你追踪到了dll里的数据,说明你有dll的源码,建议把这个结构体改了,弄那么多指针干什么,c#操作起来那么麻烦

#8


引用 7 楼 lc316546079 的回复:
你这里获得的size是多少
int size = Marshal.SizeOf(myucvACF);

dll中 sizeof(ucvACF)获得的大小又是多少;
-----------------------
既然你说你追踪到了dll里的数据,说明你有dll的源码,建议把这个结构体改了,弄那么多指针干什么,c#操作起来那么麻烦


dll中不用计算这个的大小,直接传结构体指针就行了,不过我用C在外面定义了一个一样的结构体试了一下,两个大小还真不一样。代码是师兄给的,只说让我用C#搭界面,如果把那个结构体改了,得改好多地方

#9


如果你师兄不能给封装个c#的接口,并且测试通过,那么你就换一个项目吧。

#10


c++中的指针,意味着可能“胡写乱写,并没有确定的最终含义。

既然是可以协作的,那么凡是这种接口应该让底层的c++程序员去写,并且调试通过。或者让c#程序原来按照自己的要求制定接口规范,然后c++程序去实现。

#11


引用 8 楼 tianxiaoying22 的回复:
dll中不用计算这个的大小,直接传结构体指针就行了,不过我用C在外面定义了一个一样的结构体试了一下,两个大小还真不一样。代码是师兄给的,只说让我用C#搭界面,方


从你贴出的两段代码可以看出来,你连 顺序都不一样,说明你不是从c++那种比较低级的面向字节顺序的角度去理解c++,而是从c#的高级的面向类型的角度去理解c++。你现在还没有理解c和c++语言啊。

#12





引用 11 楼 sp1234 的回复:
Quote: 引用 8 楼 tianxiaoying22 的回复:

dll中不用计算这个的大小,直接传结构体指针就行了,不过我用C在外面定义了一个一样的结构体试了一下,两个大小还真不一样。代码是师兄给的,只说让我用C#搭界面,方


从你贴出的两段代码可以看出来,你连 顺序都不一样,说明你不是从c++那种比较低级的面向字节顺序的角度去理解c++,而是从c#的高级的面向类型的角度去理解c++。你现在还没有理解c和c++语言啊。


额 我大学学的不是计算机,只在大一简单的学过几天C, 所以.........

#13


要改很多东西?
且不谈那么多指针,就算在c/c++中管理内存会稍显麻烦;
就c#的使用来说全是intptr每次的get要 ptr to struct,每次set要struct to ptr.........累。。。
还有那数组。。。。c#的数组在堆里结构体只保留指针,c/c++那数组是实际存放在结构体里。。。
c++提供给c#的接口,最好要c# c/c++都了解的人来封装更合适,里面更多的是c#的认识,我的建议是由一个 真正 熟悉c#且了解c/c++的人来定义及封装;如果没有,那就让你自己做那个人。。。

另外我提议你获取两边的size意思是让你明白两边结构体并不对应,根据差多少字节,去思考了解c# c/c++关于结构体在内存中的存放原理。

#14


C#中全用指针即可,取值也用指针,操作方便简单,目前我还没遇到过不能成功的结构体

#15


引用 14 楼 bigbaldy 的回复:
C#中全用指针即可,取值也用指针,操作方便简单,目前我还没遇到过不能成功的结构体


什么叫取值也用指针,我昨天代码贴错了,结构体顺序是一致的,穿进去了,dll里的数据也正确,所以我觉得应该在向外拷数据的时候出的错,我是通过下面的方法将mluv里的数据考到图片中的
int bytes = curBitmap.Width * curBitmap.Height * 3;
byte[] luv = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);
System.Runtime.InteropServices.Marshal.Copy(luv, 0, ptr, bytes);//其中ptr是Tntptr类型,指向图片首地址
如果用C/C++的话是这样操作的
for (int i = 0; i < height; i++)
{
for (int j = 0; j < widthStep; j += step)
{
im.data[i*widthStep+j] = (unsigned char)UucvACF->mluv[i*widthStep+j];
im.data[i*widthStep+j+1] = (unsigned char)UucvACF->mluv[i*widthStep+j+1];
im.data[i*widthStep+j+2] = (unsigned char)UucvACF->mluv[i*widthStep+j+2];
}
}
结果是C#中的luv里的数据和C中im.data[]里的数据不一样,我在想是不是copy()出了错,或者是类型对应有错误
谢谢各位了

#16


这得按顺序啊,封送过程其实就是内存数据传递

所以,你内存顺序不同,结果自然不可知。话说你这样乱串居然没木溢出也算是个小奇迹了

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct ucvACF {
    
    /// float*
    public System.IntPtr ucvTemp;
    
    /// float*
    public System.IntPtr ucvGx;
    
    /// float*
    public System.IntPtr ucvGy;
    
    /// float*
    public System.IntPtr angles;
    
    /// int*
    public System.IntPtr ucvGray;
    
    /// float*[6]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=6, ArraySubType=System.Runtime.InteropServices.UnmanagedType.SysUInt)]
    public System.IntPtr[] hist;
    
    /// float*[10]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=10, ArraySubType=System.Runtime.InteropServices.UnmanagedType.SysUInt)]
    public System.IntPtr[] channels;
    
    /// int*[10]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=10, ArraySubType=System.Runtime.InteropServices.UnmanagedType.SysUInt)]
    public System.IntPtr[] acf_channels;
    
    /// int
    public int mW;
    
    /// int
    public int mH;
    
    /// int
    public int dimensions;
    
    /// float*
    public System.IntPtr mLUV;
    
    /// float*
    public System.IntPtr ucvGradMag;
}


#17


不好意思各位,我C的代码贴错了,顺序一样,
typedef struct ucvACF
{
int mW,mH,dimensions;
float *mLUV;
float *ucvGradMag;
        float *ucvTemp;
float *ucvGx;
float *ucvGy;
float *angles;
int *ucvGray;

float *hist[6];
float *channels[10];
int *acf_channels[10];
}

#18


引用 16 楼 wanghui0380 的回复:
这得按顺序啊,封送过程其实就是内存数据传递

所以,你内存顺序不同,结果自然不可知。话说你这样乱串居然没木溢出也算是个小奇迹了

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct ucvACF {
    
    /// float*
    public System.IntPtr ucvTemp;
    
    /// float*
    public System.IntPtr ucvGx;
    
    /// float*
    public System.IntPtr ucvGy;
    
    /// float*
    public System.IntPtr angles;
    
    /// int*
    public System.IntPtr ucvGray;
    
    /// float*[6]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=6, ArraySubType=System.Runtime.InteropServices.UnmanagedType.SysUInt)]
    public System.IntPtr[] hist;
    
    /// float*[10]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=10, ArraySubType=System.Runtime.InteropServices.UnmanagedType.SysUInt)]
    public System.IntPtr[] channels;
    
    /// int*[10]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=10, ArraySubType=System.Runtime.InteropServices.UnmanagedType.SysUInt)]
    public System.IntPtr[] acf_channels;
    
    /// int
    public int mW;
    
    /// int
    public int mH;
    
    /// int
    public int dimensions;
    
    /// float*
    public System.IntPtr mLUV;
    
    /// float*
    public System.IntPtr ucvGradMag;
}


不好意思我代码贴错了,现在的问题是这个:
我追到dll里边,发现dll里的数据正确,所以我觉得应该在向外拷数据的时候出的错,我是通过下面的方法将mluv里的数据考到图片中的
int bytes = curBitmap.Width * curBitmap.Height * 3;
byte[] luv = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);
System.Runtime.InteropServices.Marshal.Copy(luv, 0, ptr, bytes);//其中ptr是Tntptr类型,指向图片首地址
如果用C/C++的话是这样操作的
for (int i = 0; i < height; i++)
{
for (int j = 0; j < widthStep; j += step)
{
im.data[i*widthStep+j] = (unsigned char)UucvACF->mluv[i*widthStep+j];
im.data[i*widthStep+j+1] = (unsigned char)UucvACF->mluv[i*widthStep+j+1];
im.data[i*widthStep+j+2] = (unsigned char)UucvACF->mluv[i*widthStep+j+2];
}
}
结果是C#中的luv里的数据和C中im.data[]里的数据不一样,我在想是不是copy()出了错,或者是类型对应有错误

#19


引用 10 楼 sp1234 的回复:
c++中的指针,意味着可能“胡写乱写,并没有确定的最终含义。

既然是可以协作的,那么凡是这种接口应该让底层的c++程序员去写,并且调试通过。或者让c#程序原来按照自己的要求制定接口规范,然后c++程序去实现。


大家没有人懂C#。。。。。都是用C/C++
我昨天代码贴错了,两个结构体顺序一致,现在问题是这样的,我追到dll里边,发现dll里的数据正确,所以我觉得应该在向外拷数据的时候出的错,我是通过下面的方法将mluv里的数据考到图片中的
int bytes = curBitmap.Width * curBitmap.Height * 3;
byte[] luv = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);
System.Runtime.InteropServices.Marshal.Copy(luv, 0, ptr, bytes);//其中ptr是Tntptr类型,指向图片首地址
如果用C/C++的话是这样操作的
for (int i = 0; i < height; i++)
{
for (int j = 0; j < widthStep; j += step)
{
im.data[i*widthStep+j] = (unsigned char)UucvACF->mluv[i*widthStep+j];
im.data[i*widthStep+j+1] = (unsigned char)UucvACF->mluv[i*widthStep+j+1];
im.data[i*widthStep+j+2] = (unsigned char)UucvACF->mluv[i*widthStep+j+2];
}
}
结果是C#中的luv里的数据和C中im.data[]里的数据不一样,我在想是不是copy()出了错,或者是类型对应有错误

您觉得是什么原因呢

#20


有关你最后一个问题,inptr只是一个指针,按照你的东西,我觉着你可以使用BitmapData去接收

#21


BitmapData 设置好宽高,范围后。直接把Scan0 的指针指向到你获取到的那个intptr上看看

#22


如果c++ 那段代码里 widthStep 是 width *3 且 step 是3的话,那你这样copy就不该有错;
你可以先在dll中看mLUV指向的地址是多少,再在c#中看是多少,对比是否一致;
如果一致,再拿copy以后bytes里的数据,和dll中mLUV数据做对比看怎么个不一样法

#23


引用 22 楼 lc316546079 的回复:
如果c++ 那段代码里 widthStep 是 width *3 且 step 是3的话,那你这样copy就不该有错;
你可以先在dll中看mLUV指向的地址是多少,再在c#中看是多少,对比是否一致;
如果一致,再拿copy以后bytes里的数据,和dll中mLUV数据做对比看怎么个不一样法


两个地址一样,但是两个数据完全不一样,dll中mluv的数据是正确的,bytes里不对

#24


引用 22 楼 lc316546079 的回复:
如果c++ 那段代码里 widthStep 是 width *3 且 step 是3的话,那你这样copy就不该有错;
你可以先在dll中看mLUV指向的地址是多少,再在c#中看是多少,对比是否一致;
如果一致,再拿copy以后bytes里的数据,和dll中mLUV数据做对比看怎么个不一样法


dll中mluv的前五个数分别为,70 29 84 70 29;bytes中为11 219 141 66 8。这有什么规律在里边吗,我实在看不出来。

#25


引用 21 楼 wanghui0380 的回复:
BitmapData 设置好宽高,范围后。直接把Scan0 的指针指向到你获取到的那个intptr上看看


我的ptr本来是指向原图的Scan0,现在我ptr = myucvACF1.mLUV,结果输出原图,没有变;;可是我用上边的方法,结果是雪花,这是什么原因

#26


引用 24 楼 tianxiaoying22 的回复:
Quote: 引用 22 楼 lc316546079 的回复:

如果c++ 那段代码里 widthStep 是 width *3 且 step 是3的话,那你这样copy就不该有错;
你可以先在dll中看mLUV指向的地址是多少,再在c#中看是多少,对比是否一致;
如果一致,再拿copy以后bytes里的数据,和dll中mLUV数据做对比看怎么个不一样法


dll中mluv的前五个数分别为,70 29 84 70 29;bytes中为11 219 141 66 8。这有什么规律在里边吗,我实在看不出来。

一步一步找错,既然你说dll 里看到的 mLUVd地址和c#里看到的一样,那就比数据,
在System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);断点
查看myucvACF1.mLUV地址,复制, 去菜单的 调试->窗口->内存 里查看该地址的数据,和dll中时 mLUV是否一致;
在地址一致时,数据肯定也是一致的,如果不对,只能是你哪里细节说错了,且你自认为没错

#27


引用 26 楼 lc316546079 的回复:
Quote: 引用 24 楼 tianxiaoying22 的回复:

Quote: 引用 22 楼 lc316546079 的回复:

如果c++ 那段代码里 widthStep 是 width *3 且 step 是3的话,那你这样copy就不该有错;
你可以先在dll中看mLUV指向的地址是多少,再在c#中看是多少,对比是否一致;
如果一致,再拿copy以后bytes里的数据,和dll中mLUV数据做对比看怎么个不一样法


dll中mluv的前五个数分别为,70 29 84 70 29;bytes中为11 219 141 66 8。这有什么规律在里边吗,我实在看不出来。

一步一步找错,既然你说dll 里看到的 mLUVd地址和c#里看到的一样,那就比数据,
在System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);断点
查看myucvACF1.mLUV地址,复制, 去菜单的 调试->窗口->内存 里查看该地址的数据,和dll中时 mLUV是否一致;
在地址一致时,数据肯定也是一致的,如果不对,只能是你哪里细节说错了,且你自认为没错


C#可以看内存吗?我怎么看不了,查了一下好像说不让看

#28


C#中调用c++dll的结构体传递问题

#29


引用 27 楼 tianxiaoying22 的回复:
Quote: 引用 26 楼 lc316546079 的回复:

Quote: 引用 24 楼 tianxiaoying22 的回复:

Quote: 引用 22 楼 lc316546079 的回复:

如果c++ 那段代码里 widthStep 是 width *3 且 step 是3的话,那你这样copy就不该有错;
你可以先在dll中看mLUV指向的地址是多少,再在c#中看是多少,对比是否一致;
如果一致,再拿copy以后bytes里的数据,和dll中mLUV数据做对比看怎么个不一样法


dll中mluv的前五个数分别为,70 29 84 70 29;bytes中为11 219 141 66 8。这有什么规律在里边吗,我实在看不出来。

一步一步找错,既然你说dll 里看到的 mLUVd地址和c#里看到的一样,那就比数据,
在System.Runtime.InteropServices.Marshal.Copy(myucvACF1.mLUV, luv, 0, bytes);断点
查看myucvACF1.mLUV地址,复制, 去菜单的 调试->窗口->内存 里查看该地址的数据,和dll中时 mLUV是否一致;
在地址一致时,数据肯定也是一致的,如果不对,只能是你哪里细节说错了,且你自认为没错


C#可以看内存吗?我怎么看不了,查了一下好像说不让看


。。。。谁说不让看。。。我在mac下没有vs不能截图,但是“菜单 调试->窗口->内存”这样打开的调试窗口是可以看内存的,大概菜单式这么点,没vs在手上我也不确定你去菜单里找找