Borland C ++ Builder LoadFromResourceID导致违反EAccess

时间:2018-08-12 23:04:36

标签: c++ bitmap c++builder vcl

我正在使用Borland C ++ Builder 5编写游戏程序。我正在尝试从我创建的资源文件中加载位图。我无法从中加载位图 资源文件(按ID或按名称)。它将从文件加载,但是我想要 使用资源文件。从ID或名称加载会在运行时导致以下错误消息:

  

项目HoldemProbs.exe引发带有消息的异常类EAcessViolation   '模块'HoldemProbs.exe'中地址0043F66E的访问冲突。   读取地址000003EB。进程已停止。使用“步骤”或“运行”继续。

我对C ++和C ++ Builder还是很陌生,我确信自己做错了什么。我只是不知道是什么。我认为它可能与HInstance的值有关,但是我不知道是什么。

下面是相关的代码段:

ResRC.h

#ifndef RESRC_H 
#define RESRC_H
#define RC_REDBACK 1000
#endif

RedBack.rc

RC_REDBACK BITMAP "<MYSOURCEPATH>\RedBack.bmp"

HoldemProbs.cpp

#include <vcl.h>
#pragma hdrstop
USERES("HoldemProbs.res");
USEFORM("..\Source\HoldemCalc.cpp", Form1);
USERES("..\Source\RedBack.res");

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    try
    {
        Application->Initialize();
        Application->Title = "HoldemEval";
        Application->CreateForm(__classid(TForm1), &Form1);
        Application->Run();
    }
    catch (Exception &exception)
    {
        Application->ShowException(&exception);
    }
    return 0;
}

HoldemCalc.cpp

#include <vcl.h>
#include <cstring.h>
#include <HoldemEval.hpp>
#include <Graphics.hpp>
#pragma hdrstop
#pragma resource "*.dfm"
#include <Graphics.hpp>
#include <ResRC.h>
#include "HoldemCalc.h"
#include <string>

#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    CardBackTst();               //Run test of card back bitmap useage
}

CardBackTst.cpp

void CardBackTst(void){
    Graphics::TBitmap* RedBack = new Graphics::TBitmap;
    Form1 -> Debug -> Text = DEBUGTEXT;     //See below for DEBUGTEXT
    RedBack -> LoadFromResourceID ((ARG1),RC_REDBACK); //See below for ARG1                      
}

有一个名为Debug的编辑框,用于显示调试信息。在不同时间,DEBUGTEXT(没有围绕" s):

"(int)(GetModuleHandle(NULL)"
"reinterpret_cast<int>(HInstance)"
"(int)HInstance"
"(int)(GetModuleHandle("<MYFINALPATH>\\HoldemProbs.exe"))"   // ANSI string
"RC_REDBACK"                     (This yielded the correct value -- 1000)     
"reinterpret_cast<int>(RedBack -> Handle)"
"(int)(Form1 -> Handle)"

在不同的时间,ARG1DEBUGTEXT的上述每个值,除了RC_REDBACK。所有这些都导致了EAccessViolation错误。

已使用以下从资源名称加载的语句 每个ARG1值,并具有相同的EAcessViolation结果:

RedBack -> LoadFromResourceName ((ARG1),"MYPATH\\RedBack.bmp"); 

但是,下面的LoadFromFile()语句可以从实际的位图文件中加载:

RedBack -> LoadFromFile("MYPATH\\RedBack.bmp");

1 个答案:

答案 0 :(得分:0)

我看到此代码有两个问题:

  • RedBack.rc没有#include "ResRC.h"语句:

    #include "ResRC.h" // <-- add this!
    RC_REDBACK BITMAP "<MYSOURCEPATH>\RedBack.bmp"
    

    否则,RC_REDBACK将不会被#define删除,因此位图资源将由文字名称"RC_REDBACK"而不是ID号1000来标识。因此,您将不得不使用LoadFromResouceName()而不是LoadFromResourceID()

    RedBack->LoadFromResourceName((unsigned)HInstance, "RC_REDBACK");
    

    使用资源查看器工具来验证最终可执行文件中如何实际标识您的资源。

  • CardBackTst()内的
  • 中,可能尚未分配全局Form1指针,因为仍在构造TForm1对象。 CardBackTst() 完全不应该依赖全局指针。应该使用Form指针作为输入参数:

    //#include "ResRC.h"
    
    void CardBackTst(TForm1 *Form) {
        Graphics::TBitmap* RedBack = new Graphics::TBitmap;
        if (Form) Form->Debug->Text = DEBUGTEXT;
        //RedBack->LoadFromResourceID((unsigned)HInstance, RC_REDBACK);
        RedBack->LoadFromResourceName((unsigned)HInstance, "RC_REDBACK");
    }
    
    ...
    
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
        CardBackTst(this);
    }
    

    更好的解决方案是直接传递TEdit而不是TForm本身:

    //#include "ResRC.h"
    
    void CardBackTst(TEdit *Debug) {
        Graphics::TBitmap* RedBack = new Graphics::TBitmap;
        if (Debug) Debug->Text = DEBUGTEXT;
        //RedBack->LoadFromResourceID((unsigned)HInstance, RC_REDBACK);
        RedBack->LoadFromResourceName((unsigned)HInstance, "RC_REDBACK");
    }
    
    ...
    
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
        CardBackTst(Debug);
    }
    

    或者,改用回调函数:

    //#include "ResRC.h"
    
    typedef void __fastcall (__closure *TCardDebugProc)(const String &);
    
    void CardBackTst(TCardDebugProc DebugProc) {
        Graphics::TBitmap* RedBack = new Graphics::TBitmap;
        if (DebugProc) DebugProc(DEBUGTEXT);
        //RedBack->LoadFromResourceID((unsigned)HInstance, RC_REDBACK);
        RedBack->LoadFromResourceName((unsigned)HInstance, "RC_REDBACK");
    }
    
    ...
    
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
        CardBackTst(&LogDebug);
    }
    
    void __fastcall TForm1::LogDebug(const String &DebugText)
    {
        Debug->Text = DebugText;
    }