【问题标题】:insufficient buffer when call DocumentProperties, also, global unlock wouldn't unlock调用 DocumentProperties 时缓冲区不足,全局解锁也无法解锁
【发布时间】:2023-03-16 10:18:01
【问题描述】:

请看 cmets inline

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

【问题讨论】:

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

标签: c++ windows printing getlasterror


【解决方案1】:

如果对 DocumentProperties() 的第二次调用返回 1(即 IDOK),那么它没有失败,因此 GetLastError() 的值是没有意义的。这可能是在 DocumentProperties() 内部提出和处理的预期条件。使用 GetLastError() 的惯例是你只在失败时设置它;你通常不会在成功时清除它。由每个单独函数的文档来解释如何返回错误。 DocumentProperties() 的文档甚至没有提到 GetLastError(),因此检查它可能毫无意义(尽管通常可以安全地假设所有 Win32 函数都通过 GetLastError() 返回错误)。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      在某些情况下,DocumentProperties 将针对某些机器的 DEVMODE 大小返回 -1 - MS 论坛上有一个关于它的完整主题(开始于 2008 年左右)但 MS 并不认为这是一个问题,尽管他们的示例代码从未检查返回码(或 PrintDlg() 常见对话框,它愉快地尝试分配 -1 内存并失败)。

      您不能仅仅依赖此功能,因为它可以在您的机器上运行,但在客户的机器上却失败了。检查 -1,如果它返回只是组成一个大数字(2*sizeof(DEVMODE) 或其他东西)并使用它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-09-17
        • 1970-01-01
        • 2016-07-24
        • 2014-04-11
        • 2011-09-06
        • 1970-01-01
        • 2011-01-23
        • 1970-01-01
        相关资源
        最近更新 更多