C++ 调用DocumentProperties时缓冲区不足,而且全局解锁将';t解锁

C++ 调用DocumentProperties时缓冲区不足,而且全局解锁将';t解锁,c++,windows,printing,getlasterror,C++,Windows,Printing,Getlasterror,请参阅内联评论 bool res = false; DWORD dwNeeded = DocumentPropertiesW(NULL, m_currPrinterHandle, (LPWSTR) m_currPrinterName.c_str(), NULL, NULL, 0); if (m_devmode_buf) { GlobalFree(m_devmode_buf); } m_devmode_buf = GlobalAlloc(GPTR, dwNeeded); Ge

请参阅内联评论

bool res = false;
DWORD dwNeeded = DocumentPropertiesW(NULL, m_currPrinterHandle, (LPWSTR) m_currPrinterName.c_str(), NULL, NULL, 0); 
if (m_devmode_buf)
{
    GlobalFree(m_devmode_buf);      
}
m_devmode_buf = GlobalAlloc(GPTR, dwNeeded);
GetLastError(); // = 0;
if (m_devmode_buf)
{
    LPDEVMODEW devmode_buf = (LPDEVMODEW) GlobalLock(m_devmode_buf);        
    GetLastError(); // = 0
    if (devmode_buf)
    {           
        if (devmode_buf)
        {
            lala = DocumentPropertiesW(NULL, m_currPrinterHandle, (LPWSTR) m_currPrinterName.c_str(), devmode_buf, NULL, DM_OUT_BUFFER);
            if (lala == IDOK)
            {
                res = true;
            }
            GetLastError(); // = 122. insufficient buffer here. why????
        }
        UInt32 res1 = GlobalUnlock(m_devmode_buf); // res1 is 1. should be 0
        res2 = GetLastError(); // = 0
        if (!(res1 == 0 && (res2 == ERROR_NOT_LOCKED || res2 == NO_ERROR)))
        {
            //res = false;
        }           
    }
}

您不需要调用GlobalLock,因为您已将GPTR传递给GlobalAlloc。当您通过GMEM_MOVEABLE时,只需调用GlobalLock


但是,您不应该使用GlobalAlloc/GlobalFree,除非您将内存传递给的API的文档另有说明。更喜欢HeapAlloc/HeapFree或只是new/delete。GlobalAlloc是一种较旧的API,旨在与16位Windows兼容。

如果对DocumentProperties()的第二次调用返回1(即IDOK),则不会失败,因此GetLastError()的值没有意义。这可能是在DocumentProperties()中引发和处理的预期条件。使用GetLastError()的惯例是只在失败时设置它;你通常不会在成功时就明白这一点。解释如何返回错误取决于每个函数的文档。DocumentProperties()的文档甚至没有提到GetLastError(),因此检查它可能毫无意义(尽管通常可以安全地假设所有Win32函数都通过GetLastError()返回错误).

DocumentProperties在某些情况下会返回-1,表示特定机器的DEVMODE大小-MS论坛上有一个完整的线程(开始于2008年左右),但MS不认为这是一个问题,尽管示例代码从未检查返回代码(或PrintDlg()很高兴尝试分配-1内存但失败的公共对话框)


你不能仅仅依靠这个功能,因为它可以在你的机器上工作,但在客户端的机器上失败。检查-1,如果它返回的是一个大数字(2*sizeof(DEVMODE)或其他什么),则使用它。

转换到LPWSTR永远都不正确。如果必须,请使用DocumentPropertiesA()。对DocumentProperties()的第二次调用是否实际失败?在这种情况下,返回小于0的值表示失败。如果没有失败,那么GetLastError()的值就没有意义了。@Hans Passant m_currPrinterName是std::wstring,我认为这样强制转换是安全的。@Luke对DocumentProperties()的第二次调用返回1。我还在第二次调用DocumentProperties()之前调用GetLastError()。GetLastError()在调用DocumentProperties()之前返回0,但在调用DocumentProperties()之后返回122。只有在函数返回失败时才调用GetLastError()。如果你不需要的话就不要投,这会让阅读你代码的人感到困惑。