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 - 发布/调试中的不同返回的主要内容,如果未能解决你的问题,请参考以下文章