C# 调用DLL多级指针和多维数组问题。

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);
    }
}

官方实例地址:

封送类、结构和联合 - .NET Framework | Microsoft Learn

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值