ROOT GUI on Windows 10 with visual studio 2022


I would like to write a standalone C++ program based on ROOT v6.30.02 in Windows 10 with Visual Studio 2022 and CMake. When we run this program, I would like to show a window with left part a button and the right part a TCanvas, and when I click the button, it will print a message in terminal.
The code has been tested on Mac/Linux systems. However, on Windows, it can be compiled correctly, but with a run-time error on the generated file “G__MyMainFrame.cxx” L176:

Unhandled exception at 0x00007FFA7B90CF19 in root_cmake.exe: Microsoft C++ exception: std::length_error at memory location 0x00000097F5FDFB50.

If I use x64_release to compile the project, it will give me the errors in the terminal:

IncrementalExecutor::executeFunction: symbol '?GeneratorConfig@MyMainFrame@@QEAAXXZ' unresolved while linking symbol '__cf_3'!
You are probably missing the definition of public: void __cdecl MyMainFrame::GeneratorConfig(void) __ptr64
Maybe you need to load the corresponding shared library?
Error in <TClingCallFunc::make_wrapper>: Failed to compile
  ==== SOURCE BEGIN ====
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-security"
__attribute__((used)) __attribute__((annotate("__cling__ptrcheck(off)")))
extern "C" void __cf_3(void* obj, int nargs, void** args, void* ret)
{
   ((MyMainFrame*)obj)->GeneratorConfig();
   return;
}
#pragma clang diagnostic pop
  ==== SOURCE END ====
Error in <TClingCallFunc::Exec(address, interpVal)>: Called with no wrapper, not implemented!

Could anyone give me some hints?
Many thanks.
Zhihong Shen

The following is my project:
CMakelist.txt:

cmake_minimum_required(VERSION 3.16)

project("root_cmake")

# Find the ROOT package
find_package(ROOT REQUIRED COMPONENTS Gui)

# Include directories
include_directories(${ROOT_INCLUDE_DIRS})
include_directories(${CMAKE_SOURCE_DIR}/include)

# Specify C++ Standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# ROOT dictionary generation
ROOT_GENERATE_DICTIONARY(G__MyMainFrame ${CMAKE_SOURCE_DIR}/include/MyMainFrame.h LINKDEF ${CMAKE_SOURCE_DIR}/include/LinkDef.h)

# Add executable
add_executable(root_cmake "src/main.cpp" "src/MyMainFrame.cpp" "G__MyMainFrame.cxx")  # Add the generated dictionary to the list of source files

# Link ROOT libraries
target_link_libraries(root_cmake PUBLIC ${ROOT_LIBRARIES})

include/LinkDef.h:

#ifdef __CINT__

#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C++ class MyMainFrame+;

#endif

include/MyMainFrame.h:

#endif // MY_MAIN_FRAME_H

#ifndef MY_MAIN_FRAME_H
#define MY_MAIN_FRAME_H

#include <TGFrame.h>
#include <TGButton.h>
#include <TRootEmbeddedCanvas.h>
#include <iostream>

class MyMainFrame {
private:
    TGMainFrame* fMain;
    TRootEmbeddedCanvas* fEmbeddedCanvas;
    TGHorizontalFrame* fHFrame;
    TGVerticalFrame* fLeftFrame;
    TGTextButton* fButton;
    void SetupGUI(int width, int height);
public:
    MyMainFrame(const TGWindow* p, int width, int height);
    virtual ~MyMainFrame();
    void GeneratorConfig();  
    ClassDef(MyMainFrame, 0)
};

src/main.cpp:

#include "MyMainFrame.h"
#include "TApplication.h"

int main(int argc, char** argv) {
    TApplication theApp("App", &argc, argv);
    MyMainFrame* mainFrame = new MyMainFrame(gClient->GetRoot(), 2000, 900);
    theApp.Run();
    delete mainFrame;
    return 0;
}

src/MyMainFrame.cpp:

#include "MyMainFrame.h"
#include <TCanvas.h>
#include <TH1D.h>
#include <TRandom.h>

MyMainFrame::MyMainFrame(const TGWindow* p, int width, int height) {
    fMain = new TGMainFrame(p, width, height);
    SetupGUI(width, height);
}

MyMainFrame::~MyMainFrame() {
    fMain->Cleanup();
    delete fMain;
}

void MyMainFrame::SetupGUI(int width, int height) {
    fHFrame = new TGHorizontalFrame(fMain, width, height);
    fLeftFrame = new TGVerticalFrame(fHFrame, width / 2, height);
    fButton = new TGTextButton(fLeftFrame, "Generator Config");
    fButton->Connect("Clicked()", "MyMainFrame", this, "GeneratorConfig()");
    fLeftFrame->AddFrame(fButton, new TGLayoutHints(kLHintsCenterX | kLHintsTop, 200, 200, 5, 5));
    fHFrame->AddFrame(fLeftFrame, new TGLayoutHints(kLHintsLeft | kLHintsExpandY));

    fEmbeddedCanvas = new TRootEmbeddedCanvas("EmbeddedCanvas", fHFrame, width / 2, height);
    fHFrame->AddFrame(fEmbeddedCanvas, new TGLayoutHints(kLHintsRight | kLHintsExpandX | kLHintsExpandY));

    TCanvas* canvas = fEmbeddedCanvas->GetCanvas();
    TH1D* h1 = new TH1D("h1", "Example histogram", 100, -4, 4);
    for (int i = 0; i < 10000; i++) {
        h1->Fill(gRandom->Gaus(0, 1));
    }
    h1->Draw();
    canvas->Update();

    fMain->AddFrame(fHFrame, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
    fMain->MapSubwindows();
    fMain->Resize(fMain->GetDefaultSize());
    fMain->MapWindow();

 //   fButton->Connect("Clicked()", "MyMainFrame", this, "GeneratorConfig()");
    // ...
}

void MyMainFrame::GeneratorConfig() {
    std::cout << "Generator Config button pressed!" <<std::endl;
    // MyGuiHandler::GeneratorConfig 中的代码
    // ...
}

_ROOT Version: 6.30.02
_Platform: Windows10
_Compiler: visual studio 2022


Add set(CMAKE_CXX_FLAGS ${ROOT_CXX_FLAGS}), set_target_properties(root_cmake PROPERTIES ENABLE_EXPORTS 1), and set_target_properties(root_cmake PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE) in your CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)

project("root_cmake")

# Find the ROOT package
find_package(ROOT REQUIRED COMPONENTS Gui)

# Include directories
include_directories(${ROOT_INCLUDE_DIRS})
include_directories(${CMAKE_SOURCE_DIR}/inc)

# Specify C++ Standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS ${ROOT_CXX_FLAGS})

# ROOT dictionary generation
ROOT_GENERATE_DICTIONARY(G__MyMainFrame ${CMAKE_SOURCE_DIR}/inc/MyMainFrame.h LINKDEF ${CMAKE_SOURCE_DIR}/inc/LinkDef.h)

# Add executable
add_executable(root_cmake src/main.cpp src/MyMainFrame.cpp G__MyMainFrame.cxx)  # Add the generated dictionary to the list of source files
set_target_properties(root_cmake PROPERTIES ENABLE_EXPORTS 1)
set_target_properties(root_cmake PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)

# Link ROOT libraries
target_link_libraries(root_cmake PUBLIC ${ROOT_LIBRARIES})

Thanks a lot for advice.
It works!!!

Best Wishes,
Zhihong.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.