我正在使用Swig为DLL文件生成python包装器。我所做的是:
swig -c++ -python
myfile.i
接口文件如下所示:
%module myfile
/* Make a test with cpointer - needed?? */
%include cpointer.i
%pointer_functions(MyHandle, my_handle_p);
%pointer_class(int, intp);
%{
#define SWIG_FILE_WITH_INIT
#include "MyFile.h"
}%
%include "MyFile.h"
该功能看起来像
typedef struct tagMyHandle
{
void* reserved;
} *MyHandle;
int OpenFile(const char *szPath, MyHandle* pFile); // pFile is an out parameter
int GetNumberOfItems(MyHandle hFile, int *pnNrOfItems); // pnNrOfItems is an out parameter
如果我尝试从Python中使用它,我必须这样做:
import myfile
handle_p = myfile.new_my_handle_p()
myfile.OpenFile("Path", handle_p)
handle = myfile.my_file_p_value(handle_p)
num_items_p = myfile.new_intp()
myfile.GetNumberOfItems(handle, num_items_p)
num_items = num_items_p.value()
我是否正确使用Swig?感觉这是一种非常麻烦的方式来调用应该为Python包装的函数。
我想做点什么:
result, handle = OpenFile("path")
result, items = GetNumberIfItems(handle)
我无法更改myfile.h的源代码。
我看了input/output parameters,但我是否必须为每种输出类型定义它们? MyFile.h有数百个具有不同输出类型的函数。它只支持原始数据类型,但MyFile.h中的大多数类型都不是原始类型,而是像结构MyHandle一样。
我也看过SWIG function with pointer struct和http://www.swig.org/Doc3.0/Python.html#Python_nn18,但没有任何好的解决方案。
更新1 经过很多帮助后,我已经解决了大部分问题,但我仍然有一些我不明白的问题。
问题1:
// For the out parameter, shouldn't be needed?
%typemap(in,numinputs=0) MyHandle* pOutParam (MyHandle h) %{
$1 = &h;
%}
// For all others
%typemap(in,numinputs=0) MyHandle* (MyHandle h) %{
$1 = &h;
%}
// For the return type
%typemap(argout) MyHandle* pOutParam (PyObject* o) %{
o = PyLong_FromVoidPtr(*$1);
$result = SWIG_Python_AppendOutput($result,o);
%}
%typemap(in) MyHandle %{
$1 = reinterpret_cast<MyHandle>(PyLong_AsVoidPtr($input));
%}
和代码
int OpenFile(const char *szPath, MyHandle* pOutParam);
int DoSomething(MyHandle* pInParam);
OpenFile
就像魅力一样,但DoSomething
仍尝试返回MyHandle
而不是将其作为参数,我不明白为什么。 %typemap(argout) MyHandle*
仅定义为pOutParam
。
问题2: 我不明白如何制作像
这样的类型地图int GetFileName(char *szPathBuffer, int iLength);
如何创建一个char缓冲区并将其发送到,如I C:
char szBuffer[MAX_PATH]; GetFileName(szBuffer, MAX_PATH);
也许和cstring_bounded_output
一起或者我应该做点什么
%typemap(in) (char*, int) {
$2 = PyString_Size($input);
$1 = (char*) malloc($2 * sizeof(char*));
}
但它在何处被解除分配?
问题3: 枚举值的正确映射是什么。如果我有
typedef enum tagMyEnum {
MyTrue = 1,
MyFalse = 0 } MyEnum;
和功能
int IsCorrect(MyEnum* pOutValue);
@Mark Tolonen: 谢谢大家的帮助!对此,我真的非常感激!我学到了很多关于Swig的新东西!
答案 0 :(得分:1)
这是一个示例,其界面类似于您想要使用类型图重新定义界面的说明:
<强> myfile.h 强>
typedef struct tagMyHandle
{
void* reserved;
} *MyHandle;
int OpenFile(const char *szPath, MyHandle* pFile);
int GetNumberOfItems(MyHandle hFile, int *pnNrOfItems);
// Added this to free the allocated handle.
void CloseFile(MyHandle hFile);
<强> MYFILE.CPP 强>
标题的黑客实现......
#include "myfile.h"
int OpenFile(const char *szPath, MyHandle* pFile)
{
*pFile = new tagMyHandle;
(*pFile)->reserved = new int(7);
return 1;
}
int GetNumberOfItems(MyHandle hFile, int *pnNrOfItems)
{
*pnNrOfItems = *reinterpret_cast<int*>(hFile->reserved) + 5;
return 1;
}
// mirrors OpenFile to free the allocated handle.
void CloseFile(MyHandle hFile)
{
delete reinterpret_cast<int*>(hFile->reserved);
delete hFile;
}
<强> myfile.i 强>
%module myfile
%{
#include "MyFile.h"
%}
// An input typemap for the an output parameter, called before the C++ function is called.
// It suppresses requiring the parameter from Python, and uses a temporary
// variable to hold the output value.
%typemap(in,numinputs=0) MyHandle* (MyHandle h) %{
$1 = &h;
%}
// An output argument typemap, called after the C++ function is called.
// It retrieves the output value and converts it to a Python int,
// then appends it to the existing return value. Python will get a tuple of
// (return_value,handle).
%typemap(argout) MyHandle* (PyObject* o) %{
o = PyLong_FromVoidPtr(*$1);
$result = SWIG_Python_AppendOutput($result,o);
%}
// An input typemap that converts a Python int to a MyHandle*.
%typemap(in) MyHandle %{
$1 = reinterpret_cast<MyHandle>(PyLong_AsVoidPtr($input));
%}
// This applies a pre-defined int* output typemap to all int* parameters.
%apply int *OUTPUT {int *};
%include "MyFile.h"
<强>输出强>
>>> import myfile
>>> s,h = myfile.OpenFile('path')
>>> s,h
(1, 7706832)
>>> s,v = myfile.GetNumberOfItems(h)
>>> s,v
(1, 12)
>>> myfile.CloseFile(h)