【问题标题】:Borland C++ Builder LoadFromResourceID Results in EAccess ViolationBorland C++ Builder LoadFromResourceID 导致 EAccess 冲突
【发布时间】:2019-01-19 15:59:24
【问题描述】:

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

Project HoldemProbs.exe 引发异常类 EAcessViolation 并显示消息 'HoldemProbs.exe' 模块中地址 0043F66E 的访问冲突。 读取地址 000003EB。进程停止。使用 Step 或 Run 继续。

我对 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)"

在不同的时间,ARG1 一直是DEBUGTEXT 的上述每个值,RC_REDBACK 除外。所有这些都导致了EAccessViolation 错误。

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

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

但是,从实际位图文件加载的以下LoadFromFile() 语句确实有效:

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

【问题讨论】:

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


    【解决方案1】:

    我发现这段代码有两个问题:

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

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

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

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

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

    • CardBackTst() 内部,可能尚未分配全局Form1 指针,因为TForm1 对象仍在构建中。 CardBackTst() 不应该完全依赖全局指针。它应该将表单指针作为输入参数:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-10
      • 2012-12-08
      • 1970-01-01
      • 1970-01-01
      • 2011-08-08
      • 2022-01-07
      • 2010-09-25
      • 1970-01-01
      相关资源
      最近更新 更多