Strange behavior reading TFile in Windows

Hello ROOTers,
I have observed some unexpected behavior when doing a very simple test in Windows. I have built using MSVS 2010 and root-builder from the svn v5-28-00 tag. I compile a program in MSVS with all of the normal included libs (libCore, libHist, etc.) and everything works as expected in most situations. However, when I try to open a file containing TH2F’s and read one in using this code,

// includes not shown...
int _tmain(int argc, _TCHAR* argv[])
{
   TFile *fin=new TFile("a.root","READ");
   TH2F *h=0;
   fin->GetObject("hist",h);
   fin->Close();
}

I get the following errors:

Warning in <TClass::TClass>: no dictionary for class TH2F is available
Warning in <TClass::TClass>: no dictionary for class TH2 is available
Warning in <TClass::TClass>: no dictionary for class TH1 is available
Warning in <TClass::TClass>: no dictionary for class TAxis is available

and the program fails to get the histogram from the file.

If I modify the program slightly to instantiate a dummy TH2F object before I try to open the file,

int _tmain(int argc, _TCHAR* argv[])
{
    TH2F *hDummy=new TH2F("dummy","dummy",10,0,10,10,0,10); 
    hDummy->SetDirectory(0);
    TFile *fin=new TFile("a.root","READ");
    TH2F *h=0;
    fin->GetObject("hist",h);
    fin->Close();
}

then everything works as expected.

Is this reproducible for others or localized to my setup? It’s not a huge problem since I can easily instantiate dummies, but I would rather not if there’s some trivial way to fix this.

Thanks in advance,
Dan

fin->GetObject(“hist”, h);
(o.k., I can see you’ve corrected it already.)

This was an error in my transcription of the code. I saw that and edited it right before you posted the correction.

I assume you have “#include <TH2.h>” among your includes.

Indeed I do or else it would not compile. I am having a run-time error.

I don’t think this is a proper solution but for test purposes you might try to load the “Hist” library manually:
#include <TSystem.h>
int _tmain(int argc, _TCHAR* argv[])
{
gSystem->Load(“libHist”);
TFile *fin=new TFile(“a.root”,“READ”);

Hi Dan,

You should create an instance of TApplication at the beginning of your code:

Cheers, Bertrand.

That works! It must be some kind of auto-loading problem but it doesn’t make sense to me. I’m not using CINT here, just the ROOT libraries, so I don’t understand why the TH2 symbols in the linked dll are not visible to the program. Can anybody else reproduce this behavior?

[quote=“Pepe Le Pew”]I don’t think this is a proper solution but for test purposes you might try to load the “Hist” library manually:
#include <TSystem.h>
int _tmain(int argc, _TCHAR* argv[])
{
gSystem->Load(“libHist”);
TFile *fin=new TFile(“a.root”,“READ”);
…[/quote]

Why does he need TApplication?

I knew that this had to be done for programs using the windowing system , but the program I have above is a simple win32 console application that just needs the ROOT libraries. It is still necessary in that case as well?

[quote=“bellenot”]Hi Dan,

You should create an instance of TApplication at the beginning of your code:

Cheers, Bertrand.[/quote]

The autoloading mechanism is done for you by TApplication when reading a TFile. If you don’t want to create a TApplication, then you have to do it yourself…

Cheers, Bertrand.

Ok. It is no problem to make a TApplication at the beginning of the program. I guess the part that is confusing for me is that when I write terminal programs in Linux that use the ROOT libraries I don’t have to make a TApplication object, so I expected the same behavior in Windows. Is autoloading handled differently in Linux than it is in Windows?

Thanks for the help,
Dan

[quote=“bellenot”]The autoloading mechanism is done for you by TApplication when reading a TFile. If you don’t want to create a TApplication, then you have to do it yourself…

Cheers, Bertrand.[/quote]

Are you sure that the same (exactly same) code works on Linux? I’ll check, but the behavior should be more or less the same (the dynamic loading of libraries is different on Windows and Linux…)

Cheers, Bertrand

I don’t get it either.
According to your original main, you explicitly link your executable against the “Hist” shared library, so no autoloading feature for “TH2” should be needed. No matter whether it’s Linux or Windows.
Maybe you could you try another test …

int _tmain(int argc, _TCHAR* argv[])
{
    TH1F *hDummy=new TH1F("dummy","dummy",10,0,10);
    hDummy->SetDirectory(0);
    TFile *fin=new TFile("a.root","READ");
    TH2F *h=0;
    fin->GetObject("hist",h);
    fin->Close();
}

We create a “TH1F” (which comes from the “Hist” library, too).
Do you still get the same problems with “TH2F” now?
If yes, then I don’t get it at all.
If no, then it means that the linker linked the “Hist” library now, because it found that it’s needed for “TH1F”, while if no “TH1” nor “TH2” were explicitly used, then the reference to the “Hist” library was “optimized-out” from the list of libraries of the executable.

Linking doesn’t mean loading… if no symbol is needed (e.g. no instance of TH2F), the library is not loaded. This is also why this line:

in the original code was solving the problem…(it was forcing the loading of the library).
Otherwise, liking with all the dlls would load all the dlls in memory, even if no symbol is needed (that would be quite a waste of memory…). I hope this clarify a bit how dynamic libraries work (at least on Windows)

Cheers, Bertrand.

There exists the “delayed loading” (delayed import?) - the shared library gets automatically loaded first when it’s really needed.
Hence, you can have your executable linked against any number of shared libraries, but they will not be loaded into memory until they are really needed.
I thought the Windows linker supported it, too.

This page http://en.wikipedia.org/wiki/Dynamic-link_library#Delayed_loading indicates that delayed loading is available for Windows dlls. Is there some switch I have to turn on in the MSVS solution configuration to get it to work or is this some kind of ROOT bypass of the standard mechanism?

Hi,

See the /INCLUDE (Force Symbol References) linker flag, and add one (or more) of these flags to your project (but at least /include:_G__cpp_setupG__Hist in your case):

/include:_G__cpp_setupG__G3D /include:_G__cpp_setupG__GPad /include:_G__cpp_setupG__Graf /include:_G__cpp_setupG__Hist /include:_G__cpp_setupG__Matrix /include:_G__cpp_setupG__Physics /include:_G__cpp_setupG__PostScript /include:_G__cpp_setupG__Rint /include:_G__cpp_setupG__Tree
Hope this helps.
Cheers, Bertrand.