1、数组和循环指针
C语言接口:结构体中含本身的指针myApi_sIp *pNext;
#pragma once
#ifndef _DLL_API
#ifdef DLL_EXPORTS
#define _DLL_API _declspec(dllexport)
#else
#define _DLL_API _declspec(dllimport)
#endif
#endif // !_DLL_API
struct myApi_sIp
{
char szIp[40];
myApi_sIp *pNext;
};
typedef void(_stdcall * myApi_Call) (myApi_sIp *p,int nNum);
extern "C" _DLL_API int _stdcall MyApi_Test(int *a, myApi_sIp **b);
extern "C" _DLL_API void _stdcall MyApi_EndTest(myApi_sIp *b);
extern "C" _DLL_API void _stdcall MyApi_CallBack(myApi_Call pFun);
C#使用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct myApi_sIp
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
public string szIp;
public IntPtr pNext;
}
namespace ConsoleApp1
{
class Program
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void myApi_Call(IntPtr p, int num2);
[DllImport("ConsoleApplication3.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int MyApi_Test(ref int a, out IntPtr b);
[DllImport("ConsoleApplication3.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void MyApi_EndTest(IntPtr b);
[DllImport("ConsoleApplication3.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void MyApi_CallBack(myApi_Call b);
static void Main(string[] args)
{
//指针
{
IntPtr v;
int nNum = 0;
MyApi_Test(ref nNum, out v);
myApi_sIp r;
for (int i = 0; i < nNum; i++)
{
IntPtr ptr = new IntPtr(v.ToInt32() + Marshal.SizeOf(typeof(myApi_sIp)) * i);
r = (myApi_sIp)Marshal.PtrToStructure(ptr, typeof(myApi_sIp));
Console.WriteLine(ptr.ToString());
}
IntPtr pNext = v;
while (IntPtr.Zero != pNext)
{
r = (myApi_sIp)Marshal.PtrToStructure(pNext, typeof(myApi_sIp));
pNext = r.pNext;
Console.WriteLine(pNext.ToString());
}
MyApi_EndTest(v);
}
{
//回调
MyApi_CallBack((IntPtr p, int num2) =>
{
myApi_sIp r;
IntPtr pNext = p;
while (IntPtr.Zero != pNext)
{
r = (myApi_sIp)Marshal.PtrToStructure(pNext, typeof(myApi_sIp));
pNext = r.pNext;
Console.WriteLine(pNext.ToString());
}
});
}
GC.Collect();
Console.ReadKey();
}
}
}
2、结构体含多级指针
C语言结构体
struct TYSearch_SeverInfo {
char szIp[20][80]; //ip地址
};
C#取巧做法:
[StructLayout(LayoutKind.Sequential)]
public struct TYSearch_SeverInfoIpString
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string strIp;
};
[StructLayout(LayoutKind.Sequential)]
public struct TYSearch_SeverInfo
{
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 20)]
public TYSearch_SeverInfoIpString[] szIp; //ip地址
};
C#正常做法:需要使用Marshal进行转换。
[StructLayout(LayoutKind.Sequential)]
public struct TYSearch_SeverInfo
{
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 20 * 80)]
public byte[] szIp; //ip地址
};
3、多级指针
C++接口:
PINVOKELIB_API int TestRefArrayOfInts( int** ppArray, int* pSize )
{
int result = 0;
// CoTaskMemAlloc must be used instead of the new operator
// because code on the managed side will call Marshal.FreeCoTaskMem
// to free this memory.
int* newArray = (int*)CoTaskMemAlloc( sizeof(int) * 5 );
for ( int i = 0; i < *pSize; i++ )
{
result += (*ppArray)[i];
}
for ( int j = 0; j < 5; j++ )
{
newArray[j] = (*ppArray)[j] + 100;
}
CoTaskMemFree( *ppArray );
*ppArray = newArray;
*pSize = 5;
return result;
}
C#两种使用方式:
internal static unsafe class NativeMethods
{
// Declares managed prototypes for the unmanaged function.
[DllImport("..\\LIB\\PInvokeLib.dll")]
internal static extern void TestOutArrayOfStructs(
out int size, out IntPtr outArray);
[DllImport("..\\LIB\\PInvokeLib.dll")]
internal static extern void TestOutArrayOfStructs(
out int size, MyUnsafeStruct** outArray);
}
public class App
{
public static void Main()
{
Console.WriteLine("\nUsing marshal class\n");
UsingMarshaling();
Console.WriteLine("\nUsing unsafe code\n");
UsingUnsafePointer();
}
public static void UsingMarshaling()
{
int size;
IntPtr outArray;
NativeMethods.TestOutArrayOfStructs(out size, out outArray);
MyStruct[] manArray = new MyStruct[size];
IntPtr current = outArray;
for (int i = 0; i < size; i++)
{
manArray[i] = new MyStruct();
Marshal.PtrToStructure(current, manArray[i]);
//Marshal.FreeCoTaskMem((IntPtr)Marshal.ReadInt32(current));
Marshal.DestroyStructure(current, typeof(MyStruct));
current = (IntPtr)((long)current + Marshal.SizeOf(manArray[i]));
Console.WriteLine("Element {0}: {1} {2}", i, manArray[i].buffer,
manArray[i].size);
}
Marshal.FreeCoTaskMem(outArray);
}
public static unsafe void UsingUnsafePointer()
{
int size;
MyUnsafeStruct* pResult;
NativeMethods.TestOutArrayOfStructs(out size, &pResult);
MyUnsafeStruct* pCurrent = pResult;
for (int i = 0; i < size; i++, pCurrent++)
{
Console.WriteLine("Element {0}: {1} {2}", i,
Marshal.PtrToStringAnsi(pCurrent->buffer), pCurrent->size);
Marshal.FreeCoTaskMem(pCurrent->buffer);
}
Marshal.FreeCoTaskMem((IntPtr)pResult);
}
}
官方实例地址: