GUI Issues in Visual C++

Hi,

I am using VS 2019 with ROOT 6.18 to generate a GUI that should plot a sinx/x graph when the Draw button is clicked and close when the Exit button is clicked however I am having issues. This is an example found in p. 570 of the ROOT guide. I have looked at other posts that have similar problems and a solution that worked but I haven’t been able to understand it. I believe the solution involves dictionaries (which I am unfamiliar with).

In myFrame.h, when the line ClassDef(MyMainFrame, 0) is commented out, the GUI opens and the Exit button works but when it is included, I get the following errors:

  1. myFrame.obj : error LNK2019: unresolved external symbol “public: static class TClass * __cdecl MyMainFrame::Class(void)” (?Class@MyMainFrame@@SAPAVTClass@@XZ) referenced in function "public: virtual class TClass * __thiscall MyMainFrame::IsA(void)const " (?IsA@MyMainFrame@@UBEPAVTClass@@XZ)

  2. myFrame.obj : error LNK2019: unresolved external symbol “public: virtual void __thiscall MyMainFrame::Streamer(class TBuffer &)” (?Streamer@MyMainFrame@@UAEXAAVTBuffer@@@Z) referenced in function “[thunk]:public: virtual void __thiscall MyMainFrame::Streamer`adjustor{48}’ (class TBuffer &)” (?Streamer@MyMainFrame@@WDA@AEXAAVTBuffer@@@Z)

ex2aLinkDef.h

#pragma link C++ class MyMainFrame;

myFrame.h

#include <TQObject.h>
#include <TApplication.h>
#include <TGClient.h>
#include <TCanvas.h>
#include <TF1.h>
#include <TRandom3.h>
#include <TGButton.h>
#include <TGFrame.h>
#include <TRootEmbeddedCanvas.h>
#include <RQ_OBJECT.h>
#include "ex2aLinkDef.h"


class MyMainFrame : public TGMainFrame {

private:

	TRootEmbeddedCanvas* fEcanvas;

public:

	MyMainFrame(const TGWindow* p, UInt_t w, UInt_t h);

	virtual ~MyMainFrame();

	void DoDraw();

	void doClose(void);

	//ClassDef(MyMainFrame, 0)

};

myFrame.cpp

#include "myFrame.h"
#include "ex2aLinkDef.h"


MyMainFrame::MyMainFrame(const TGWindow* p, UInt_t w, UInt_t h)

	: TGMainFrame(p, w, h) {

	// Creates widgets of the example

	fEcanvas = new TRootEmbeddedCanvas("Ecanvas", this, 200, 200);

	AddFrame(fEcanvas, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY,

		10, 10, 10, 1));

	TGHorizontalFrame* hframe = new TGHorizontalFrame(this, 200, 40);

	TGTextButton* draw = new TGTextButton(hframe, "&Draw");

	draw->Connect("Clicked()", "MyMainFrame", this, "DoDraw()");

	hframe->AddFrame(draw, new TGLayoutHints(kLHintsCenterX, 5, 5, 3, 4));

	TGTextButton* exit = new TGTextButton(hframe, "&Exit ",

		"gApplication->Terminate()");

	hframe->AddFrame(exit, new TGLayoutHints(kLHintsCenterX, 5, 5, 3, 4));

	AddFrame(hframe, new TGLayoutHints(kLHintsCenterX, 2, 2, 2, 2));

	// Sets window name and shows the main frame

	SetWindowName("Simple Example");

	MapSubwindows();

	Resize(GetDefaultSize());

	MapWindow();

}

void MyMainFrame::DoDraw() {

	// Draws function graphics in randomly chosen interval

	TF1* f1 = new TF1("f1", "sin(x)/x", 0, gRandom->Rndm() * 10);

	f1->SetFillColor(19);

	f1->SetFillStyle(1);

	f1->SetLineWidth(3);

	f1->Draw();

	TCanvas* fCanvas = fEcanvas->GetCanvas();

	fCanvas->cd();

	fCanvas->Update();

}

MyMainFrame::~MyMainFrame() {

	// Clean up used widgets: frames, buttons, layouthints

}

void MyMainFrame::doClose()

{

	gApplication->Terminate(0);

}

RootProject.cpp

#include <TApplication.h>
#include <TF1.h>
#include <TRandom3.h>
#include "myFrame.h"
#include "ex2aLinkDef.h"


int main(int argc, char** argv)
{
	TApplication theApp("App", &argc, argv);

	new MyMainFrame(gClient->GetRoot(), 200, 200);

	theApp.Run();

	return 0;

}

Thanks!

And how do you compile it?

I am running it in debug in VS.

That was not my question… Anyway, you have to generate a dictionary for your project and include it in the list of source files. Something like:

rootcling -f exa2aDict.cxx -c myFrame.h ex2aLinkDef.h

(you can probably add this command in some custom build step in Visual Studio)
Then add exa2aDict.cxx in the list of source files in your project.

Thank you. I just put the line in cmd and it generated a exa2aDict.cxx. I then added this to the source files and ran the program. It is throwing me exceptions now in the exa2aDict.cxx file.

OK, I’ll take a look and let you know.

Alright thanks :smile:

OK, so doing it by hand works for me, if you keep (un-comment) ClassDef(MyMainFrame, 0) in myFrame.h, and if you export myMainFrame::DoDraw(). So in the command prompt, if I do:

C:\Users\bellenot\rootdev\Aaron>rootcling -f exa2aDict.cxx -c myFrame.h ex2aLinkDef.h

C:\Users\bellenot\rootdev\Aaron>cl -MD -GR -EHsc -I%ROOTSYS%\include myFrame.cpp exa2aDict.cxx RootProject.cpp /link -LIBPATH:%ROOTSYS%\lib libCore.lib libRIO.lib libHist.lib libGraf.lib libGpad.lib libGui.lib libMathcore.lib /export:?DoDraw@MyMainFrame@@QAEXXZ /out:ex2a.exe

then it works.

Thank you. However when I put that second line in cmd it says " ‘cl’ is not recognised as an internal or external command, operable program or batch file."

You have to use a x86 Native Tools Command Prompt for VS 2019

Thank you.

I have done this in my Developer Command Prompt but there are still exceptions thrown in the exa2aDict.cxx whenever I run the program in VS.

This is the output I receive from the export in the VS Command Prompt.

C:\VS\myRootProject\myRootProject>rootcling -f exa2aDict.cxx -c myFrame.h ex2aLinkDef.h

C:\VS\myRootProject\myRootProject>cl -MD -GR -EHsc -I%ROOTSYS%\include myFrame.cpp exa2aDict.cxx myRootProject.cpp /link -LIBPATH:%ROOTSYS%\lib libCore.lib libRIO.lib libHist.lib libGraf.lib libGpad.lib libGui.lib libMathcore.lib /export:?DoDraw@MyMainFrame@@QAEXXZ /out:ex2a.exe
Microsoft (R) C/C++ Optimizing Compiler Version 19.21.27702.2 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

myFrame.cpp
C:\root_v6.18.00\include\ROOT\libcpp_string_view.h(193): warning C4068: unknown pragma
C:\VS\myRootProject\myRootProject\ex2aLinkDef.h(1): warning C4068: unknown pragma
C:\VS\myRootProject\myRootProject\ex2aLinkDef.h(1): warning C4068: unknown pragma
exa2aDict.cxx
C:\root_v6.18.00\include\ROOT\libcpp_string_view.h(193): warning C4068: unknown pragma
C:\VS\myRootProject\myRootProject\ex2aLinkDef.h(1): warning C4068: unknown pragma
myRootProject.cpp
C:\root_v6.18.00\include\ROOT\libcpp_string_view.h(193): warning C4068: unknown pragma
C:\VS\myRootProject\myRootProject\ex2aLinkDef.h(1): warning C4068: unknown pragma
C:\VS\myRootProject\myRootProject\ex2aLinkDef.h(1): warning C4068: unknown pragma
Generating Code...
Microsoft (R) Incremental Linker Version 14.21.27702.2
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:myFrame.exe
-LIBPATH:C:\root_v6.18.00\lib
libCore.lib
libRIO.lib
libHist.lib
libGraf.lib
libGpad.lib
libGui.lib
libMathcore.lib
/export:?DoDraw@MyMainFrame@@QAEXXZ
/out:ex2a.exe
myFrame.obj
exa2aDict.obj
myFirstRootProject.obj
   Creating library ex2a.lib and object ex2a.exp

What do you mean? What kind of exception? Can you run (execute) ex2a.exe from that command prompt? If it works, then you have to adapt your project to match this simple example (in particular the compiler flags)

I can execute the example ex2a.exe from the command prompt and it works.

The exception is:

Unhandled exception at 0x759A2C92 in myRootProject.exe: Microsoft C++ exception: std::bad_array_new_length at memory location 0x012FF590.

thrown at line 173 of the exa2aDict.cxx which looks something like:

#undef  _BACKWARD_BACKWARD_WARNING_H
)DICTPAYLOAD";
    static const char* classesHeaders[]={
"MyMainFrame", payloadCode, "@",
nullptr};

    static bool isInitialized = false;
    if (!isInitialized) {
      TROOT::RegisterModule("exa2aDict",                                  //LINE 173
        headers, includePaths, payloadCode, fwdDeclCode,
        TriggerDictionaryInitialization_exa2aDict_Impl, {}, classesHeaders, /*has no C++ module*/false);
      isInitialized = true;
    }
  }
  static struct DictInit {
    DictInit() {
      TriggerDictionaryInitialization_exa2aDict_Impl();
    }
  } __TheDictionaryInitializer;
}
void TriggerDictionaryInitialization_exa2aDict() {
  TriggerDictionaryInitialization_exa2aDict_Impl();
}

I’m not sure what you mean by adapting my project to match the example.

You have a Visual Studio solution, right? Then you have to set the options to have the same compiler flags than the ones used in the command prompt. or don’t use Visual Studio solution projects, but simply the command prompt…
And you confirm that ex2a.exe doesn’t throw any exception, right?

Yes I can confirm that running from the command prompt that ex2a.exe works correctly.

I do have a VS solution however I’m not sure how to set the compiler flags.

Look in your solution’s properties

see for example:

Thanks. I have looked at that a bit now but I am unsure of where I should add compiler flags and where to find the compiler flags I need to add.