【问题标题】:0xC0000005: Access violation after calling CopyMemory()0xC0000005:调用 CopyMemory() 后访问冲突
【发布时间】:2012-12-16 06:41:29
【问题描述】:

当我取消注释创建位图的代码行时,我遇到了第一次机会异常错误。我以与我制作的其他 sprite 相同的方式创建了这个 spritesheet BMP。错误信息是这样的:

First-chance exception at 0x004788ca in HenwayRevamped.exe: 0xC0000005: Access violation writing location 0x02224000.

我正在运行基于 Michael Morrison 的 GameEngine 类构建的游戏。我已经对此错误进行了几个小时的研究,包括许多 StackOverflow 线程和this handy site,但我仍然不确定问题出在哪里。这是函数调用

// Create a bitmap from a resource
Bitmap::Bitmap(HDC hDC, UINT uiResID, HINSTANCE hInstance)
  : m_hBitmap(NULL), m_iWidth(0), m_iHeight(0)
{
  Create(hDC, uiResID, hInstance);
}

这是函数

BOOL Bitmap::Create(HDC hDC, UINT uiResID, HINSTANCE hInstance)
{
  // Free any previous DIB info
  Free();

  // Find the bitmap resource
  HRSRC hResInfo = FindResource(hInstance, MAKEINTRESOURCE(uiResID), RT_BITMAP);
  if (hResInfo == NULL)
    return FALSE;

  // Load the bitmap resource
  HGLOBAL hMemBitmap = LoadResource(hInstance, hResInfo);
  if (hMemBitmap == NULL)
    return FALSE;

  // Lock the resource and access the entire bitmap image
  PBYTE pBitmapImage = (BYTE*)LockResource(hMemBitmap);
  if (pBitmapImage == NULL)
  {
    FreeResource(hMemBitmap);
    return FALSE;
  }

  // Store the width and height of the bitmap
  BITMAPINFO* pBitmapInfo = (BITMAPINFO*)pBitmapImage;
  m_iWidth = (int)pBitmapInfo->bmiHeader.biWidth;
  m_iHeight = (int)pBitmapInfo->bmiHeader.biHeight;

  // Get a handle to the bitmap and copy the image bits
  PBYTE pBitmapBits;
  m_hBitmap = CreateDIBSection(hDC, pBitmapInfo, DIB_RGB_COLORS,
    (PVOID*)&pBitmapBits, NULL, 0);
  if ((m_hBitmap != NULL) && (pBitmapBits != NULL))
  {
    const PBYTE pTempBits = pBitmapImage + pBitmapInfo->bmiHeader.biSize +
      pBitmapInfo->bmiHeader.biClrUsed * sizeof(RGBQUAD);


    CopyMemory(pBitmapBits, pTempBits, pBitmapInfo->bmiHeader.biSizeImage);

    // Unlock and free the bitmap graphics object
    UnlockResource(hMemBitmap);
    FreeResource(hMemBitmap);
    return TRUE;
  }

  // Something went wrong, so cleanup everything
  UnlockResource(hMemBitmap);
  FreeResource(hMemBitmap);
  Free();
  return FALSE;
}

另外,这是我的带有本地窗口的 IDE 的屏幕截图。装订线中的绿色箭头图标指向引发异常的行:

Image Hosted by ImageShack.us http://imageshack.us/a/img341/7678/20121216010703am.png

是我的设备上下文有问题吗? hDC 变量下的红色感叹号图标看起来可能指向问题,但它分配了一个句柄,所以我不确定。我的想法已经用完了,正在求助于大师。

【问题讨论】:

  • 您可能已经知道,这与从您在帖子中首先列出的构造函数中触发的 Create() 调用不同。该代码触发Create(),需要设备上下文、宽度、高度和颜色。您显示的不相关的Create() 正在加载资源位图(或至少尝试加载)。
  • pBitmapInfo->bmiHeader 里面有什么?我预计biSizeImage 的值在那里是错误的。
  • 感谢@WhozCraig 的提醒;我错误地发布了错误的重载调用。实际调用现在在 OP 中。 @Roman,该调用返回 147458。从图像的 Windows 属性窗口中,图像大小为 147512。如果这是问题,我该如何解决?
  • 我看到的是你有 768x64 的图像。我看不到它的位数,假设它是 24 位/像素。因此,总共 147456 个字节。这就是biSizeImage 中应该包含的内容。我希望 API 分配这个长度的内部缓冲区。如果那里有错误的值(API 可能已忽略),则尝试复制更多字节,然后缓冲区可以容纳并因此预期。这就是为什么我认为这个值可能是错误的。

标签: c++ winapi visual-c++ memory-management


【解决方案1】:

访问冲突发生在写入时,这表明您超出了目标缓冲区。有许多不同类型的位图格式,因此很难为缓冲区计算正确的大小。您的代码确实适用于一些位图,所以我怀疑您对位深度、颜色表大小、对齐方式或这些方面的东西有一个错误的假设。

只要有可能,您不妨让 Windows 来完成这项工作:

    BOOL Bitmap::Create2(UINT uiResID, HINSTANCE hInstance) {
        BOOL bSuccess = FALSE;
        Free();
        m_hBitmap = reinterpret_cast<HBITMAP>(
            ::LoadImage(hInstance, MAKEINTRESOURCE(uiResID), IMAGE_BITMAP,
                        0, 0, LR_CREATEDIBSECTION));
        if (m_hBitmap != NULL) {
            BITMAP bmp;
            if (::GetObject(m_hBitmap, sizeof(bmp), &bmp) == sizeof(bmp)) {
                m_iWidth = bmp.bmWidth;
                m_iHeight = bmp.bmHeight;
                bSuccess = TRUE;
            }
        }
        return bSuccess;
    }

这应该适用于所有有效的位图。请注意,您不再需要将句柄传递给 DC。

【讨论】:

  • 效果很好,而且更简洁。感谢您改进我的黑客组合解决方案,该解决方案将来可能会失败!
【解决方案2】:

通常无需担心第一次机会异常,除非您更改了某些设置,否则调试器不应停止它们。未处理的异常是一个实际问题,即应用程序没有捕获和处理的异常。

如果调试器在发生时中断,您可以更改异常设置以防止将来发生这种情况,或者您可以继续查看它是否会变成未处理的异常。

更多关于第一次机会和第二次机会的信息:http://support.microsoft.com/kb/105675

【讨论】:

  • 实际上,破坏游戏功能的最初是一个未处理的异常。我第一次遇到this thread 中描述的问题,并明确勾选了“Win32 异常”复选框,因为后来出现了 wow64 仿真的错误。
【解决方案3】:

感谢 Roman 的洞察力,我能够想出这个可以正常编译和工作的解决方法。如果我对其他图像有更多异常,我将创建一个数组并遍历它,但这暂时有效:

/*  This causes strange black lines at the top of some sprites. Pixel bleeding?
    if(pBitmapInfo->bmiHeader.biSizeImage > neededBytes )
        CopyMemory(pBitmapBits, pTempBits, neededBytes);
    else
        CopyMemory(pBitmapBits, pTempBits, pBitmapInfo->bmiHeader.biSizeImage);
    */

    //workaround for powerup sprite
    if(pBitmapInfo->bmiHeader.biSizeImage == 294914 )
        CopyMemory(pBitmapBits, pTempBits, neededBytes);
    else
        CopyMemory(pBitmapBits, pTempBits, pBitmapInfo->bmiHeader.biSizeImage);

【讨论】:

    猜你喜欢
    • 2017-08-31
    • 2013-04-02
    • 1970-01-01
    • 2012-05-22
    • 2012-12-05
    • 2023-03-08
    • 1970-01-01
    • 2013-10-11
    • 1970-01-01
    相关资源
    最近更新 更多