简体   繁体   中英

C DLL and Python CTypes - Different Return in Release / Debug

I have a DLL that exists solely for the purpose of exposing a handful of Printer API Functions to Python. One of the methods looks like this:

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

This works generally as expected and I'm able to call into it with this code over in the python world:

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

And I normally expect dllopts to look like this:

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

Yes, I expect the blank string as the first entry, and the whole reason for this dll is to handle Printer Names that have Wide Character Names for language support. That's all fine and well until I build my DLL in debug mode. Then, instead of the result I expect, I get this:

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

Only one value, and every character is \? . Wat? Is that some side effect of ctypes not knowing how to deal with the dll when it's built in debug mode? Is that some effect of the memory mapping of the dll being in debug mode? I can attach to my python process (and through it, the dll as it is called into) and verify the value of result before it's returned and it looks correct, but it does not make it to my python program. I'm kind of at a loss.

You can't return a pointer managed by a local variable. When wstring result goes out of scope, using the pointer returned by result.c_str() is undefined behavior.

Examples of solutions:

  1. You could make the P_EnumPrintersW function receive a pointer, with a corresponding size information, update the memory pointed to with your final string content, and then return the pointer. The memory must be allocated in Python prior to calling the function.

  2. Another solution would be for your function to return a pointer to malloced memory. Youd would have to add another API, doing the corresponding free .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM