C++ Win32:位图实例化中断函数

C++ Win32:位图实例化中断函数,c++,winapi,bitmap,C++,Winapi,Bitmap,我的一个位图(是精灵表)有一个奇怪的问题。我的游戏运行得很好,但是如果我取消注释这行代码,初始化位图和精灵的GameStart函数就会中断: g_pPowerup100Bitmap = new Bitmap(hDC, IDB_POWERUP_100, g_hInstance); CopyMemory(pBitmapBits, pTempBits, pBitmapInfo->bmiHeader.biSizeImage); 结果是,函数在命中该行代码时退出,但必须调用GamePai

我的一个位图(是精灵表)有一个奇怪的问题。我的游戏运行得很好,但是如果我取消注释这行代码,初始化位图和精灵的GameStart函数就会中断:

g_pPowerup100Bitmap = new Bitmap(hDC, IDB_POWERUP_100, g_hInstance);
    CopyMemory(pBitmapBits, pTempBits, pBitmapInfo->bmiHeader.biSizeImage);
结果是,函数在命中该行代码时退出,但必须调用GamePaint(),因为位图会快速显示到屏幕上。我知道函数没有正确执行,因为它们不是精灵,只是图像(音乐也不会初始化)。在同一功能中,精灵和音乐初始化位于位图初始化的下方

更令人沮丧的是,这个游戏实际上是有效的……有时是有效的。然后我就可以正常玩游戏了&看新的动画精灵。然而,在尝试调试了几十次之后,它再也不能正常构建了

我所尝试的:

位图是64x1536。这是个问题吗?我有8GB的RAM和一个GTX 570分类。以下是整个功能:

void GameStart(HWND hWindow)
{
    try
  {
    // Initialize global variables
    g_iInputDelay = 0;
    g_iNumLives = 3;
    g_iScore = 0;
    g_iGameState = 1;
    g_iDifficulty = 1;

    // Seed the random number generator
    srand(GetTickCount());

    // Create the offscreen device context and bitmap
    g_hOffscreenDC = CreateCompatibleDC(GetDC(hWindow));
    g_hOffscreenBitmap = CreateCompatibleBitmap(GetDC(hWindow),
    g_pGame->GetWidth(), g_pGame->GetHeight());
    SelectObject(g_hOffscreenDC, g_hOffscreenBitmap);

    // Create and load the bitmaps
    HDC hDC = GetDC(hWindow);
    g_pHighwayBitmap = new Bitmap(hDC, IDB_HIGHWAY, g_hInstance);
    g_pChickenBitmap = new Bitmap(hDC, IDB_CHICKEN, g_hInstance);
    g_pCarBitmaps[0] = new Bitmap(hDC, IDB_CAR1, g_hInstance);
    g_pCarBitmaps[1] = new Bitmap(hDC, IDB_CAR2, g_hInstance);
    g_pCarBitmaps[2] = new Bitmap(hDC, IDB_CAR3, g_hInstance);
    g_pCarBitmaps[3] = new Bitmap(hDC, IDB_CAR4, g_hInstance);
    g_pChickenHeadBitmap = new Bitmap(hDC, IDB_CHICKENHEAD, g_hInstance);
    g_pMainMenuBitmap = new Bitmap(hDC, IDB_MAIN_MENU, g_hInstance);
    g_pHighScoresMenuBitmap = new Bitmap(hDC, IDB_HIGH_SCORES_MENU, g_hInstance);
    g_pGameOverMenuBitmap =  new Bitmap(hDC, IDB_GAME_OVER_MENU, g_hInstance);
    g_pNormalModeBtnBitmap = new Bitmap(hDC, IDB_NORMAL_MODE_BTN, g_hInstance);
    g_pHardModeBtnBitmap = new Bitmap(hDC, IDB_HARD_MODE_BTN, g_hInstance);
    g_pHighScoresBtnBitmap = new Bitmap(hDC, IDB_HIGH_SCORES_BTN, g_hInstance);
    g_pReplayBtnBitmap = new Bitmap(hDC, IDB_REPLAY_BTN, g_hInstance);
    g_pMainMenuBtnBitmap = new Bitmap(hDC, IDB_MAIN_MENU_BTN, g_hInstance);
    g_pPowerup100Bitmap = new Bitmap(hDC, IDB_POWERUP_100, g_hInstance);

    RECT    rcBounds = { 0, 0, 465, 400 };

    //Button Sprites - Main Menu
    Sprite* pBtnSprite = new Sprite(g_pNormalModeBtnBitmap, 77,228, 0,0, 1, rcBounds, BA_STOP);
    pBtnSprite->SetStateChange(0);
    g_pGame->AddSprite(pBtnSprite, 1);

    pBtnSprite = new Sprite(g_pHardModeBtnBitmap, 254,228, 0,0, 1, rcBounds, BA_STOP);
    pBtnSprite->SetStateChange(0);
    g_pGame->AddSprite(pBtnSprite, 1);

    pBtnSprite = new Sprite(g_pHighScoresBtnBitmap, 166,310, 0,0, 1, rcBounds, BA_STOP);
    pBtnSprite->SetStateChange(3);
    g_pGame->AddSprite(pBtnSprite, 1);


    //Button Sprites - Game Over Menu
    pBtnSprite = new Sprite(g_pReplayBtnBitmap, 167,249, 0,0, 1, rcBounds, BA_STOP);
    pBtnSprite->SetStateChange(0);
    g_pGame->AddSprite(pBtnSprite, 2);

    pBtnSprite = new Sprite(g_pMainMenuBtnBitmap, 82,332, 0,0, 1, rcBounds, BA_STOP);
    pBtnSprite->SetStateChange(1);
    g_pGame->AddSprite(pBtnSprite, 2);

    pBtnSprite = new Sprite(g_pHighScoresBtnBitmap, 252,332, 0,0, 1, rcBounds, BA_STOP);
    pBtnSprite->SetStateChange(3);
    g_pGame->AddSprite(pBtnSprite, 2);

    //Button Sprites - High Scores Menu
    pBtnSprite = new Sprite(g_pMainMenuBtnBitmap, 166,332, 0,0, 1, rcBounds, BA_STOP);
    pBtnSprite->SetStateChange(1);
    g_pGame->AddSprite(pBtnSprite, 3);

        // Create the chicken and car sprites
    g_pChickenSprite = new Sprite(g_pChickenBitmap, rcBounds, BA_STOP);
    g_pChickenSprite->SetPosition(4, 175);
    g_pChickenSprite->SetVelocity(0, 0);
    g_pChickenSprite->SetZOrder(1);
    g_pChickenSprite->SetNumFrames(2);
    g_pChickenSprite->SetAsInputControlled(); //stops auto-frame update
    //DEBUGGING ONLY!!!!!
    g_pChickenSprite->SetID(1);
    g_pGame->AddSprite(g_pChickenSprite, 0);

    Sprite* pSprite = new Sprite(g_pCarBitmaps[0], rcBounds, BA_WRAP);
    pSprite->SetPosition(70, 0);
    pSprite->SetVelocity(0, 6);
    pSprite->SetZOrder(2);
    g_pGame->AddSprite(pSprite, 0);
    pSprite = new Sprite(g_pCarBitmaps[1], rcBounds, BA_WRAP);
    pSprite->SetPosition(160, 0);
    pSprite->SetVelocity(0, 2);
    pSprite->SetZOrder(2);
    g_pGame->AddSprite(pSprite, 0);
    pSprite = new Sprite(g_pCarBitmaps[2], rcBounds, BA_WRAP);
    pSprite->SetPosition(239, 400);
    pSprite->SetVelocity(0, -4);
    pSprite->SetZOrder(2);
    g_pGame->AddSprite(pSprite, 0);
    pSprite = new Sprite(g_pCarBitmaps[3], rcBounds, BA_WRAP);
    pSprite->SetPosition(329, 400);
    pSprite->SetVelocity(0, -9);
    pSprite->SetZOrder(2);
    g_pGame->AddSprite(pSprite, 0);

    // Load the background music
    g_pGame->PlayMIDISong(TEXT("Music.mid"));

    getHighScores(scoreData, g_scoreTop);

    scoreData.close();

  }
  catch (int e)
  {
    cout << "An exception occurred. Exception Nr. " << e << endl;
    system("PAUSE");
  }
}
如果有人能解释为什么位图会破坏函数,我将非常感激

编辑:Hans正好击中了问题的头部-我勾选了“Win32 Exceptions”复选框&这行代码出现了内存访问错误:

g_pPowerup100Bitmap = new Bitmap(hDC, IDB_POWERUP_100, g_hInstance);
    CopyMemory(pBitmapBits, pTempBits, pBitmapInfo->bmiHeader.biSizeImage);

图像是否太大?我会继续调查,但欢迎任何建议。

正如我现在所说的,在调用GetDC后,您必须调用ReleaseDC。 但是你打了三个GetDC电话。
保留一个呼叫,存储HDC并在最后释放它。

正如我现在所说,在调用GetDC之后,您必须调用ReleaseDC。 但是你打了三个GetDC电话。
保留一个呼叫,存储HDC,并在结束时释放它。

不要使用WM_CREATE消息初始化游戏。在64位操作系统上运行32位代码时,会出现一个非常特殊的问题,当消息处理代码中出现SEH异常时,可能会导致SEH异常(如访问冲突)被吞没。WM_CREATE是显示问题的消息之一。中有很多关于此行为的详细信息,尽管它非常特定于Winforms。然而,当你在C或C++中编写代码时,同样的问题也存在。 (通常)不需要使用WM_CREATE来初始化东西,您也可以在CreateWindowsEx()调用之后移动它,因为您应该只需要窗口句柄。调试器现在将再次提供帮助,并向您显示代码崩溃的位置


如果在WM_CREATE中确实需要它,那么使用debug+异常对其进行调试,勾选Win32异常的抛出复选框。还有一种方法可以验证这个答案是否正确。

不要使用WM_创建消息来初始化游戏。在64位操作系统上运行32位代码时,会出现一个非常特殊的问题,当消息处理代码中出现SEH异常时,可能会导致SEH异常(如访问冲突)被吞没。WM_CREATE是显示问题的消息之一。中有很多关于此行为的详细信息,尽管它非常特定于Winforms。然而,当你在C或C++中编写代码时,同样的问题也存在。 (通常)不需要使用WM_CREATE来初始化东西,您也可以在CreateWindowsEx()调用之后移动它,因为您应该只需要窗口句柄。调试器现在将再次提供帮助,并向您显示代码崩溃的位置


如果在WM_CREATE中确实需要它,那么使用debug+异常对其进行调试,勾选Win32异常的抛出复选框。还有一种验证此答案是否准确的方法。

是否应该等到
WM\u CREATE
之后再使用该窗口?此函数只是将资源加载到内存中。GamePaint()是一个将它们点显到窗口的函数,稍后在程序中调用。它以窗口为参数调用
GetDC
。我想这需要一扇完工的窗户。检查
hDC
以确保它不为空。您还需要多少客户端设备上下文?您反复调用GetDC(),尽管它只应该执行一次,即使这样,您也不会释放任何东西。在确保您可以在WM_CREATE处理程序中执行这些操作后,请练习以下简单的咒语:
发布
您所获得的内容<代码>删除您创建的内容。如中所示,如果您
GetDC()
需要
ReleaseDC()
,如果您
CreateDC()
(或
CreateCompatibleDC()
),您迟早需要
DeleteDC()
。嘿,很抱歉hDC有点乱。我使用的是Michael Morrison的一个游戏引擎类和很多Windows API代码,我仍在努力理解。不过,我完全看到了GetDC问题,并修复了它。在另一个函数中,DC在每个勾号结束时释放。您是否应该等到
WM_CREATE
之后才能使用该窗口?此函数只是将资源加载到内存中。GamePaint()是一个将它们点显到窗口的函数,稍后在程序中调用。它以窗口为参数调用
GetDC
。我想这需要一扇完工的窗户。检查
hDC
以确保它不为空。您还需要多少客户端设备上下文?您反复调用GetDC(),尽管它只应该执行一次,即使这样,您也不会释放任何东西。在确保您可以在WM_CREATE处理程序中执行这些操作后,请练习以下简单的咒语:
发布
您所获得的内容<代码>删除您创建的内容。如中所示,如果您
GetDC()
需要
ReleaseDC()
,如果您
CreateDC()
(或
CreateCompatibleDC()
),您迟早需要
DeleteDC()
。嘿,很抱歉hDC有点乱。我使用的是Michael Morrison的一个游戏引擎类和很多Windows API代码,我仍在努力理解。我完全看到了GetDC pro