请教C#调用C++写的DLL的结构数组问题

gfh21cn 2013-01-03 09:36:31
C++:
struct CRoomData
{
char Name[255];
double Area;
};

struct CSystemData
{
int Count;
CRoomData *RoomDatas;
};

extern "C" bool EXPORT TestF(
CSystemData *pSysData,
int SysCount
)



C#:
    [StructLayout(LayoutKind.Sequential)]
public struct CRoomData
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
public byte []Name;
[MarshalAs(UnmanagedType.R8)]
public double Area;
}


    [StructLayout(LayoutKind.Sequential)]
public struct CSystemData
{
[MarshalAs(UnmanagedType.I4)]
public int Count;
public IntPtr RoomDatas;
}

        [DllImport("MyDll.dll", CharSet = CharSet.Ansi)]
public static extern bool TestF(
[MarshalAs(UnmanagedType.LPArray)]CSystemData[] pSysDatas,
int SysCount
);



    
public static void Copy(String pStr,byte []bufs)
{
byte[] tDatas = System.Text.Encoding.Default.GetBytes(pStr);
for (int k = 0; k < tDatas.Length&&k<bufs.Length; ++k)
bufs[k] = (byte)tDatas[k];

bufs[tDatas.Length] = (byte)0;
}
private void button7_Click(object sender, EventArgs e)
{
CSystemData[] tSys = new CSystemData[2];
for (int k = 0; k < 2; ++k)
{
tSys[k] = new CSystemData();
tSys[k].Count = 3;

CRoomData []tRoomDatas = new CRoomData[3];
for (int l = 0; l < 3; ++l)
{
tRoomDatas[l] = new CRoomData();
tRoomDatas[l].Area = 20 * l;
tRoomDatas[l].Name = new byte[255];
Copy(String.Format("房间{0}", l), tRoomDatas[l].Name);
}
IntPtrWrap<CRoomData> tW = new IntPtrWrap<CRoomData>();
tSys[k].RoomDatas = (IntPtr)tW.Wrap(tRoomDatas);
}
TestF(tSys, 2);
}


 public class IntPtrWrap<T>
{
public System.IntPtr Ip = IntPtr.Zero;
private IntPtr[] ptArray = null;
private int arrayCount = 0;
public IntPtrWrap()
{
}
/// <summary>
/// 数组类型的初始化
/// </summary>
/// <param name="pObject"></param>
public IntPtr Wrap(T[] pObject)
{
arrayCount = pObject.Length;
//分配内存
int tSize = Marshal.SizeOf(typeof(T));
ptArray = new IntPtr[1];
ptArray[0] = Marshal.AllocHGlobal(tSize * arrayCount);
//拷贝内存
for (int k = 0; k < arrayCount; ++k)
{
IntPtr tPtr = new IntPtr(ptArray[0].ToInt64() + k * tSize);
Marshal.StructureToPtr(pObject[k], tPtr, false);
}

Ip = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * 1);
Marshal.Copy(ptArray, 0, Ip, 1);
return Ip;
}
}


中间涉及到一个结构数组,我是使用的IntPtr来代替,使用Wrap方法来转换。
IntPtrWrap<CRoomData> tW = new IntPtrWrap<CRoomData>();
tSys[k].RoomDatas = (IntPtr)tW.Wrap(tRoomDatas);

调用下来,没有报错,但是我在DLL中使用日志观察传入的数据,都是些乱码,我只是觉得问题处在Wrap,但是不知道如何来解决,请各位帮我瞅瞅,出出主意。
...全文
203 4 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
gfh21cn 2013-01-04
  • 打赏
  • 举报
回复
多谢二位,问题已经解决
gomoku 2013-01-04
  • 打赏
  • 举报
回复
这里的CRoomData *RoomDatas,以及CSystemData *pSysData,应该是一个指向数组首地址的指针。 因此Wrapper不用双重指针。

public class IntPtrWrap<T> : IDisposable
{
    T[] itemsReference = null;
    IntPtr pointer = IntPtr.Zero;
    public IntPtr Pointer
    {
        get 
        {
            if (pointer == IntPtr.Zero) throw new InvalidOperationException("Pointer not initialized or destroyed");
            return pointer;
        }
    }

    public IntPtrWrap(T[] items)
    {
        int itemSize = Marshal.SizeOf(typeof(T));
        this.pointer = Marshal.AllocHGlobal(itemSize * items.Length);
        this.itemsReference = items;

        for (int i = 0; i < items.Length; i++)
        {
            Marshal.StructureToPtr(items[i], IntPtr.Add(pointer, itemSize * i), false);
        }
    }

    public void Dispose()
    {
        Marshal.FreeHGlobal(this.pointer);
        this.pointer = IntPtr.Zero;
        this.itemsReference = null;
    }

    ~IntPtrWrap()
    {
        Dispose();
        GC.SuppressFinalize(this);
    }
}
gfh21cn 2013-01-04
  • 打赏
  • 举报
回复
作为结构对象整体传入是没有问题的,我已经实验过了。 现在里面是一个结构数组,数据的错乱也包括了数值类型的变量,所以不应该是字符编码的问题。
真相重于对错 2013-01-03
  • 打赏
  • 举报
回复
msdn 有 关于平台调用 传递 类型数组的章节 如果你装了msdn2008的话 看看这ms-help://MS.MSDNQTR.v90.chs/dv_fxinterop/html/c5ac9920-5b6e-4dc9-bf2d-1f6f8ad3b0bf.htm, 你的代码比较多,没有仔细看,如果传递的乱码的话,多数和字符编码有关

111,098

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧