最近在写一个C#控制LED显示的程序,LED显示控制那儿,只提供了一个dll;
幸好,还有头文件;
例如,类似于这样的一个接口,
int DCCCALL led3_dcc_get_dtu_list(int dcc_hdl, struct dtu_unit *list, int num);
如果,返回一个列表回填到 list其实的结构内存块中;
如果你不熟悉的话,很有可能写出如下的代码:
[DllImport("led3_dcc.dll")]
public static extern int led3_dcc_get_dtu_list(int dcc_hdl,ref dtu_unit[] list, int num); 然后发现,无论如何都无法调用通过;
如果你熟悉一点的话,
[DllImport("led3_dcc.dll")]
public static extern int led3_dcc_get_dtu_list(int dcc_hdl,IntPtr pt, int num);
然后,调用 如下的方法分配一个内存块;
/// <summary>
/// 根据结构数组,产生一个非安全模式的内存块,返回该内存块的头指针;
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tAray"></param>
/// <returns></returns>
public IntPtr GetIntPtrFromStruct<T>(T[] tAray)
{
T[] result = new T[tAray.Length];
var structSize = Marshal.SizeOf(typeof(T));
IntPtr pt = Marshal.AllocHGlobal(tAray.Length * structSize);
for (var x=0; x<tAray.Length; x++)
{
Marshal.StructureToPtr(tAray[x],(IntPtr)((UInt32)pt + x * Marshal.SizeOf(typeof(T))), true);
}
return pt;
}
然后再去调用 led3_dcc_get_dtu_list 这个方法,不过这些都比较麻烦;应该有更加简单的方法;
再改改接口,
[DllImport("led3_dcc.dll")]
public static extern int led3_dcc_get_dtu_list(int dcc_hdl,ref dtu_unit firstDtuUnit, int num);
然后,
dtu_unit[] items = new dtu_unit[count];
var readCount = led3_dcc_get_dtu_list(dccHandle, ref items[0], count);
就可以了;
记得打开 /unsafe 标签。。。
至于原因,没什么好说的;
附带两个写了出来但最后没有实际用到的方法。。。看哪位兄弟有用吧;
/// <summary>
/// 利用 Func调用dll中的方法,获得一个结构的列表回来;
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="listCount"></param>
/// <param name="readSturctListFunc"></param>
/// <returns></returns>
public T[] ReadStructList<T>(int listCount, Func<IntPtr, int> readSturctListFunc)
where T : struct
{
T[] result = new T[listCount];
var structSize = Marshal.SizeOf(typeof(T));
IntPtr pt = Marshal.AllocHGlobal(listCount * structSize);
var readCount = readSturctListFunc(pt);
for (int j = 0; j < readCount; j++)
{
result[j] =
(T)Marshal.PtrToStructure((IntPtr)((UInt32)pt + j * Marshal.SizeOf(typeof(T)))
, typeof(T));
}
Marshal.Release(pt);
return result;
}
/// <summary>
/// 根据结构数组,产生一个非安全模式的内存块,返回该内存块的头指针;
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tAray"></param>
/// <returns></returns>
public IntPtr GetIntPtrFromStruct<T>(T[] tAray)
{
T[] result = new T[tAray.Length];
var structSize = Marshal.SizeOf(typeof(T));
IntPtr pt = Marshal.AllocHGlobal(tAray.Length * structSize);
for (var x=0; x<tAray.Length; x++)
{
Marshal.StructureToPtr(tAray[x],(IntPtr)((UInt32)pt + x * Marshal.SizeOf(typeof(T))), true);
}
return pt;
}
/// <summary>
/// 根据结构数组,产生一个非安全模式的内存块,返回该内存块的头指针;
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tAray"></param>
/// <returns></returns>
public IntPtr GetStructFromIntPtr<T>(IntPtr pt, int count)
{
T[] result = new T[count];
var structSize = Marshal.SizeOf(typeof(T));
for (int j = 0; j < count; j++)
{
result[j] =
(T)Marshal.PtrToStructure((IntPtr)((UInt32)pt + j * Marshal.SizeOf(typeof(T)))
, typeof(T));
}
return pt;
}