C DLL 和 Python CTypes - 发布/调试中的不同返回

Posted

技术标签:

【中文标题】C DLL 和 Python CTypes - 发布/调试中的不同返回【英文标题】:C DLL and Python CTypes - Different Return in Release / Debug 【发布时间】:2013-12-03 23:54:17 【问题描述】:

我有一个 DLL,其存在的唯一目的是向 Python 公开一些打印机 API 函数。其中一种方法如下所示:

extern "C" DOEXPORT const wchar_t* P_EnumPrintersW() 
    DWORD dwneeded(0), dwreturned(0);
    BOOL test = ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
        NULL,
        4,
        NULL,
        0,
        &dwneeded,
        &dwreturned);
    std::vector<byte> printbuf;
    printbuf.resize(dwneeded);
    test = ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
        NULL,
        4,
        &printbuf[0],
        printbuf.size(),
        &dwneeded,
        &dwreturned);
    PRINTER_INFO_4* print4 = static_cast<PRINTER_INFO_4*>((LPVOID) &printbuf[0]);
    wstring result;
    for (DWORD i = 0; i < dwreturned; ++i) 
        result += L",";
        result += print4[i].pPrinterName;
    
    return result.c_str();

这通常按预期工作,我可以在 python 世界中用这段代码调用它:

dll = ctypes.CDLL('<path to dll>')
dll.P_EnumPrintersW.restype = ctypes.c_wchar_p
dllopts = dll.P_EnumPrintersW().split(',')

我通常希望 dllopts 看起来像这样:

[u'', u'\u8fd9\u662f\u4e00\u4e2a\u8003\u9a8c', ... ]

是的,我希望空白字符串作为第一个条目,而这个 dll 的全部原因是为了处理具有宽字符名称的打印机名称以支持语言。这一切都很好,直到我在调试模式下构建我的 DLL。然后,我得到了以下结果,而不是我期望的结果:

[u'\udddd\udddd\udddd...']

只有一个值,每个字符都是\udddd。笏?这是ctypes在调试模式下构建时不知道如何处理dll的一些副作用吗?这是dll的内存映射处于调试模式的一些影响吗?我可以附加到我的python进程(并通过它,调用它的dll)并在返回之前验证result的值,它看起来正确,但它并没有进入我的python程序。我有点不知所措。

【问题讨论】:

我的回答有用吗? 你为什么不说我的回答为什么没有帮助你。很确定将本地 result.c_str() 作为 wchar_t* 返回是未定义的行为。 @manuell - 抱歉,我花了一些时间才回到这个问题并进行更多测试 - 我已经让其他项目走在了前列。 【参考方案1】:

您不能返回由局部变量管理的指针。当wstring result 超出范围时,使用result.c_str() 返回的指针是未定义的行为。

解决方案示例:

    您可以将 P_EnumPrintersW 函数 receive 设为指针, 用相应的大小信息,更新指向的内存 使用您的最终字符串内容,然后返回指针。这 在调用函数之前,必须在 Python 中分配内存。

    另一种解决方案是让您的函数返回一个指向 分配内存。 Youd 将不得不添加另一个 API,执行 对应free

【讨论】:

当我最终回到这里时,您的第一个选项解决了差异。非常感谢朋友。

以上是关于C DLL 和 Python CTypes - 发布/调试中的不同返回的主要内容,如果未能解决你的问题,请参考以下文章

python使用ctypes调用C编译dll函数方法

python引用c的dll

python--ctypes模块:调用C函数

Python调用DLL动态链接库——ctypes使用

从 python ctypes 中的 c++ dll 传递向量

platform模块和ctypes模块