/C/C++ DLL在其它语言中的调用 结构体/数组 指针

2 篇文章 0 订阅

一 结构体/数组作为返回值

 

1. Called in C#

 

c++ codes:
typedef struct TRANSACTION
{
char account[19];
int maxNum;
char startDate[16];
char endDate[16];
} TRANSACTION;

typedef struct QUERY
{
int id;
int itemAmount;
int gold;
int silver;
char itemName[30];
}QUERY;

extern "C" _declspec(dllexport) QUERY* QueryTransactionHistory(DWORD dwIP,int nPort,TRANSACTION * pTran, int* outNum,int* nErrorCode) {
cout << "dwIP = " << dwIP << ", nPort = " << nPort << ", pTran ->maxNum = " << pTran ->maxNum << endl;
cout << "pTran -> account = " << pTran ->account << ", pTran ->startDate = " << pTran ->startDate << ", pTran ->endDate = " << pTran ->endDate << endl;

QUERY* ret = (QUERY* )malloc(sizeof(QUERY) * 2);
ret[0].id = 0;
ret[0].gold = ret[0].silver = ret[0].itemAmount = 1;
strcpy(ret[0].itemName, "Item0");

ret[1].id = 1;
ret[1].gold = ret[1].silver = ret[1].itemAmount = 2;
strcpy(ret[1].itemName, "Item1");

(*outNum) = 2;
(*nErrorCode) = 0;
return ret;
}

 

C# source codes:

1. 因为返回的数组是变长的,所以DllImport函数声明不能用数组作返回类型。
   必须使用IntPtr指针做返回值,然后用Marshal.PtrToStructure读取结构内容。
 
2. 如果你在C代码中用malloc申请的返回内存,那么记得提供一个释放该内存的C函数,否则会有内存泄漏。如果用的事WindowsAPI,可以再C#中用Marshal.FreeHGlobal释放。

下面是代码:

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
    public class TRANSACTION
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 19)]
        public string  account;

        public int maxNum;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
        public string startDate;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
        public string endDate;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public class QUERY
    {
        public int id;
        public int itemAmount;
        public int gold;
        public int silver;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)]
        public string itemName;
    }

    class Program
    {
        [DllImport("CPPDLL.DLL", CallingConvention = CallingConvention.StdCall)]
        public extern static IntPtr QueryTransactionHistory(uint swIP, int nPort, TRANSACTION pTran, out int cnt, out int nErrCode);

        static void Main(string[] args)
        {
            int cnt, errCode;
            TRANSACTION tran = new TRANSACTION();

            tran.account    = "account";
            tran.endDate    = "endDate";
            tran.startDate  = "startDate";
            tran.maxNum     = 50;

            //get retrun value as IntPtr
            IntPtr ptr = QueryTransactionHistory(0, 0, tran, out cnt, out errCode);
            Console.WriteLine("============ CS ===============");
            Console.WriteLine("Count = {0}, errCode = {1}", cnt, errCode);

            IntPtr head = ptr;
            for (int i = 0; i < cnt; ++i)
            {
                //extract struct from pointer
                QUERY q = (QUERY)Marshal.PtrToStructure(ptr, typeof(QUERY));
                Console.WriteLine("id = {0}, gold = {1}, silver = {2}, itemAmount = {3}, itemName = {4}",
                    q.id, q.gold, q.silver, q.itemAmount, q.itemName);

                //move pointer by sizeof(QUERY) to the next one
                //WARNING: assume 32 bit machine!!!!!!
                ptr = (IntPtr)(ptr.ToInt32() + Marshal.SizeOf(typeof(QUERY)));
            }
            //TODO: need to free memory
        }
    }

 

二 结构体/数组作为参数

1 Python

Python调用DLL,如何使用结构体数组指针做参数


C++函数原型

typedef struct

{

    unsigned long DeviceType;

    int Handle;

    int NumberOfClients;

    int SerialNumber;

    int MaxAllowedClients;

}NeoDevice;

int _stdcall icsneoFindNeoDevices(unsigned long DeviceTypes,  NeoDevice *pNeoDevices, int *pNumberOfDevices);

Physon codes:
class NeoDevice(Structure):

    _fields_ = [("DeviceType",c_ulong),

                ("Handle",c_int),

                ("NumberOfClients",c_int),

                ("SerialNumber",c_int),

                ("MaxAllowedClients",c_int)]



class cNeoVICan(CCanBase):

    def __init__(self):

        neoVi = windll.icsneo40

        self.icsneoFindNeoDevices = neoVi.icsneoFindNeoDevices

        

if __name__ == "__main__":

    canBus = cNeoVICan()

    print canBus.icsneoGetDLLVersion()

    iNumberOfDevices = (NeoDevice * 10)()

    num = c_int()

    iResult = canBus.icsneoFindNeoDevices(c_ulong(65535), cast(iNumberOfDevices, POINT(NeoDevice)), byref(num))

 2 VB

 

  数值型数组在VB中其数据是连续存放的,相当于一维的,而在C/C++中数组可以等价于指向数组第1个元素的指针。可以用引用的方式把VB中数组的第1个元素的地址传给VC编写的DLL,在DLL中用一个指针来接收,这样就实现了VB到Dll在中数组的传递。从DLL传递数组给VB方法相同,过程相反.
    如果是二维数组,则把二维数组按照一维数组的方式传入传出,只是在使用的时候,顺便把二维数组的行和列数传递即可。
    总体思想是这样的。下面看例子。

VC中:

double _stdcall OneDimensionArrayTest(double *inArr,int nCount,double *outArr,int* ioutArrCount) //一维数组的传入传出
{
    int iNum=nCount;
     double *dRes=new double[iNum];
    int i;
     for(i=0;i<nCount;i++)
     {
         dRes[i]=inArr[i]*2;
     }

    for(i=0;i<nCount;i++)
     {
         outArr[i]=dRes[i];
     }
    *ioutArrCount=iNum;
     return dRes[0];
     delete []dRes;
}


void _stdcall TwoDimensionArrayTest(double *inArr,int nRows,int nCols,double *outArr,int* outRows,int *outCols)//二维数组的传入传出
{
     double *dRes=new double[nRows*nCols];
    int i;
     int j;
     for(i=0;i<nRows;i++)
     {
         for(j=0;j<nCols;j++)
         {
             dRes[nCols*i+j]=inArr[nCols*i+j]*2;
         }
     }
     for(i=0;i<nRows;i++)
     {
         for(j=0;j<nCols;j++)
         {
             outArr[nCols*i+j]=inArr[nCols*i+j]*2;
         }
     }
    *outRows=nRows;
     *outCols=nCols;
     delete [] dRes;
}


LIBRARY      "TestDll"

EXPORTS
    ; 此处可以是显式导出
    Add @1
    darray @2
    OneDimensionArrayTest @3
TwoDimensionArrayTest @4

VB中
Declare Function OneDimensionArrayTest Lib "D:\在编程序\Dll\VBLoadDll\TestDll.dll" (ByRef inputer As Double, ByVal inLength As Long, ByRef output As Double, ByRef outLength As Long) As Double
Declare Function TwoDimensionArrayTest Lib "D:\在编程序\Dll\VBLoadDll\TestDll.dll" (ByRef inputer As Double, ByVal inRows As Long, ByVal inCols As Long, ByRef outputer As Double, ByRef outRows As Long, ByRef outCols As Long)

Private Sub cmdTest2_Click()
Dim inputer(8) As Double
Dim out(9) As Double
Dim res As Double
Dim m As Long
inputer(0) = 1.2
inputer(1) = 2.3
inputer(2) = 1
res = OneDimensionArrayTest(inputer(0), 9, out(0), m)
MsgBox CStr(m), vbOKOnly, "一维数组的元素个数"

'MsgBox CStr(res)

Dim str As String
Dim i As Integer
For i = 0 To UBound(out)
   str = str + "   " + CStr(out(i))
Next
MsgBox str, vbOKOnly, "一维数组的元素"
End Sub

Private Sub cmdTest3_Click()
Dim iRows As Integer
Dim iCols As Integer
iRows = 3
iCols = 4
Dim inputer() As Double
ReDim inputer(iRows, iCols)
Dim outputer() As Double
ReDim outputer(iRows, iCols)
Dim oRows As Long
Dim oCols As Long
Dim i, j As Integer
For i = 0 To UBound(inputer, 1)
   For j = 0 To UBound(inputer, 2)
     inputer(i, j) = (i + 1) * (j + 1)
   Next
Next
Dim str As String
For i = 0 To UBound(inputer, 1)
   For j = 0 To UBound(inputer, 2)
      str = str + "   " + CStr(inputer(i, j))
   Next
   str = str + vbCrLf
Next
MsgBox str, vbOKOnly, "inputer,二维数组的输入"

Call TwoDimensionArrayTest(inputer(0, 0), iRows + 1, iCols + 1, outputer(0, 0), oRows, oCols)

str = ""
'
For i = 0 To UBound(outputer, 1)
   For j = 0 To UBound(outputer, 2)
      str = str + "   " + CStr(outputer(i, j))
   Next
   str = str + vbCrLf
Next
MsgBox str, vbOKOnly, "outputer,二维数组的输出"
End Sub

 

 


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值