python 调用 C++的DLL,函数参数是数组怎么处理?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 调用 C++的DLL,函数参数是数组怎么处理?相关的知识,希望对你有一定的参考价值。

最近刚学会用boost.python调用简单的c的函数,但是需要处理的是C++的类,我可以麻烦点把C++类都转化成C语言函数,但是函数参数有数组的怎么办?可以用C++的VECTOR吗,python怎么传入VECTOR?
好吧,想到个土办法,就是DLL里设个全局数组,python的数组用个循环,将数组的值一个个赋值给DLL里的全局变量。。

参考技术A

给你一个例子看看,你就知道怎么做了

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


Python调用的代码:

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

参考技术B 你既然都要手动写C了,就在C里转换成PyObject不就行了。

当参数之一是指针数组时,如何从 C# 调用 C++ DLL

【中文标题】当参数之一是指针数组时,如何从 C# 调用 C++ DLL【英文标题】:How to call C++ DLL from C# when one of the parameters is an array of pointers 【发布时间】:2017-11-27 23:32:24 【问题描述】:

我有一个 DLL pin C++,它接受两个参数,类似于 C 中的 main() 函数:参数数量,后跟指向各个参数的指针数组:

__declspec(dllexport) void Calculate(int argc, void** argv)

    if (argc >= 7)
    
        auto sourceX = *((int*)(argv[0]));
        auto sourceY = *((int*)(argv[1]));
        auto iterations = *((int*)(argv[2]));
        auto resize = *((bool*)(argv[3]));
        auto input = (double*)(argv[4]);
        auto targetX = *((int*)(argv[5]));
        auto targetY = *((int*)(argv[6]));

        // Do computations
    

我能够以这种方式从另一个 C 代码调用导出的函数(在通过 LoadLibrary 和 GetProcAddress 调用加载 DLL 库之后):

int X, Y, iterations;
bool Resize;
double* Input;

// Initialize variables, allocate data for Input
// ...

void* Params[] =  &X, &Y,  &iterations, &Resize, Input, &X, &Y ;

_Calculate(7, Params);

但是,当我尝试从 C# 调用 DLL 时,它崩溃了。这是我正在使用的 C# sn-p:

[DllImport("computedll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void Calculate(int argc, void** argv);

public void Compute()

    int X, Y, iterations;
    bool Resize;
    double* Input;

    // Initialize variables, allocate data for Input
    // ...

    var Parameters = stackalloc void*[7];

    Parameters[0] = &X;
    Parameters[1] = &Y;
    Parameters[2] = &iterations;
    Parameters[3] = &Resize;
    Parameters[4] = Input;
    Parameters[5] = &X; 
    Parameters[6] = &Y;

    Calculate(7, Parameters);

我在这里做错了什么?有没有办法使这种使用指针数组(void**)的模式起作用?提前致谢。

【问题讨论】:

见:***.com/tags/pinvoke/info 猜测您已经验证了您的 C++ 代码并且您的 C# 代码使用相同的指针大小? 【参考方案1】:

构建为 x64,以下工作。这几乎是您的代码。我讨厌在 C/C++ 之外使用 cdecl,所以如果这对你很重要……对不起。重点是...如果您遇到问题,这不是您的实际代码或概念的基础。

Interopy.h:

extern "C"

  __declspec(dllexport) void __stdcall Calculate(int argc, void** argv);

来源:

#include "Interopy.h"
void __stdcall Calculate(int argc, void** argv)

  if (argc >= 7)
  
    auto sourceX = *((int*)(argv[0]));
    auto sourceY = *((int*)(argv[1]));
    auto iterations = *((int*)(argv[2]));
    auto resize = *((bool*)(argv[3]));
    auto input = (double*)(argv[4]);
    auto targetX = *((int*)(argv[5]));
    auto targetY = *((int*)(argv[6]));
    *(int*)argv[5] = 42; //to test

    // Do computations
  

c#(平台目标 x64):

  public static class iop
  

  [DllImport("InteropyDll1.dll",  CallingConvention = CallingConvention.StdCall)]
    unsafe public static extern void Calculate(int argc, void** argv);

    unsafe static public void Compute()
    
        int X, Y, iterations;
        bool Resize;
        double* Input = (double*)IntPtr.Zero;

        // Initialize variables, allocate data for Input
        // ...

        void **Parameters = stackalloc void*[7];

        Parameters[0] = &X;
        Parameters[1] = &Y;
        Parameters[2] = &iterations;
        Parameters[3] = &Resize;
        Parameters[4] = Input;
        Parameters[5] = &X;
        Parameters[6] = &Y;

        Calculate(7, Parameters);
    
  

请注意,此程序集现在依赖于平台。我过去通过多种构建配置解决了这个问题,但我相信还有更好的方法可以解决。无论如何,出于这个原因和其他原因,您都希望将这个不安全的代码放在它自己的程序集中。

【讨论】:

谢谢你!我实施了你的建议,效果很好!我尝试对您的答案进行投票,不幸的是,我的声誉 (6) 还不够。 @StephenDaedalusSepara 不过,您始终可以接受它作为提问者。我相信它旁边有一个复选标记? @StephenDaedalusSepara - 顺便说一句,我不知道这段代码的用途,但如果你要维护它,我会留意 C# 中的 Span<T>Memory<T> 7.2.它们专为此类不需要不安全的场景而设计。不过,目前还不错。 (旧版)c++ 代码用于执行在 c# 中不可用或速度较慢的计算。是的,我会维护这些代码一段时间,直到我们得到更好的计算实现。看起来 Span<T>Memory<T> 将成为 c# 的有趣和有用的开发,再次感谢。

以上是关于python 调用 C++的DLL,函数参数是数组怎么处理?的主要内容,如果未能解决你的问题,请参考以下文章

当参数之一是指针数组时,如何从 C# 调用 C++ DLL

C# 调用C++ DLL,而c++函数的有一个参数需要是null,该怎么传递?

关于delphi调用C++的DLL中char*参数的问题

调用使用 C# 返回结构数组的非托管 dll 函数

C#:使用 char** 参数调用 C++ DLL

C#调用C++的dll库怎么传递结构体中不定长度的char数组