使用Ctypes的Void指针的C类实例

时间:2013-10-15 19:07:49

标签: python c ctypes void-pointers

我有一个C DLL,它暴露了一些方法,这些方法将void pointers返回给类,如下所示:

void *GetLicense() {
    static AppLicenseImpl ipds_;
    return (void *) &ipds_;
}

在C ++中,加载DLL后,我会这样做:

typedef void *(* FPGetLicense)();
GetLicense_ = (FPGetLicense)GetAddress("GetLicense");
license_ = (AppLicense *) GetLicense_();
license_->GetApplicationStatus(); // Load data so that other calls don't fail

我无法弄清楚如何在Python中并行化。这让我得到指针:

d = ctypes.cdll.LoadLibrary('license.dll')
d.GetLicense.restype = ctypes.c_void_p
p = d.GetLicense() # returns ptr loc, something like 8791433660848L

但我显然无法在Python中调用p.GetApplicationStatus()。有没有人建议我如何在Python中完成该类的实例化,以便我可以调用GetApplicationStatus()

2 个答案:

答案 0 :(得分:3)

引自the docs

  

有时您会遇到不兼容类型的实例。在C中,您可以将一种类型转换为另一种类型。 ctypes提供cast()函数,可以以相同的方式使用。

因此,C ++代码的Python等价物是:

license = cast(d.GetLicense(), ctypes.POINTER(AppLicense))
license.GetApplicationStatus()

然而,通常这不是必要的;你可以这样做:

d.GetLicense.restype = ctypes.POINTER(AppLicense)

这看起来像“作弊”,但事实并非如此。你只是告诉它用结果调用POINTER(AppLicense)构造函数。由于POINTER(AppLicense)是一种ctypes数据类型,因此不必首先假设结果是C int

答案 1 :(得分:1)

我花了更多的时间用这个 - 从c ++开始,当我想使用类实例时,void指针指的是我这样做:

class AppLicense {
public:
    AppLicense() {}
    virtual LicenseStatus GetApplicationStatus() = 0;
}

但我无法弄清楚如何在Python中做到这一点。这不起作用:

class AppLicense(object):
  def GetApplicationStatus(self):
    pass

所以我在dll中导出了另一个函数,如下所示:

extern "C" {
    int P_GetApplicationStatus(void *ptr) {
        try {
            AppLicenseImpl * ref = reinterpret_cast<AppLicenseImpl *>(ptr);
            return ref->GetApplicationStatus();
        } catch (...) {
            return 0; // License Error default.
        }
    }
}

一旦我掌握了这一点,就可以像这样使用它来实现:

d.GetLicense.restype = ctypes.c_void_p
p = d.GetLicense()

d.C_GetApplicationStatus.argtypes = [ctypes.c_void_p]
status = d.P_GetApplicationStatus(p)