I'm trying to build the gtkmm library using MSVC. One of its source files declares a struct called BuiltinStockID together with some objects of that type - e.g.
GTKMM_API is obviously _declspec(dllimport) (or export) as appropriate. It seems a bit unusual to use extern in addition GTKMM_API but the code won't compile if I try to exclude it. The actual instantiations are in one of the library's source files- e.g.
Code:
// In a source file
const Gtk::BuiltinStockID APPLY = { GTK_STOCK_APPLY };
const Gtk::BuiltinStockID CANCEL = { GTK_STOCK_CANCEL };
const Gtk::BuiltinStockID OK = { GTK_STOCK_OK };
GTK_STOCK_APPLY etc are simple strings such as "gtk-apply". They mostly refer to image files for the library to load (in this case, for dialog button images) although that's probably not relevant to the problem.
If I run dumpbin /EXPORTS on the built DLL it does seem to have some exported symbols with the names Gtk::Stock::APPLY, Gtk::Stock::CANCEL, Gtk::Stock::OK etc. However, if I write this in one of my own source files:-
You can see that the Gtk::Stock::CANCEL object is invalid (my debugger reports it as a bad pointer). Likewise, if I try to pass Gtk::Stock::CANCEL as a parameter to a function. What's going wrong
"A problem well stated is a problem half solved.” - Charles F. Kettering
Is the actual instantiation code in one of the library's source files ever executed? If it is, does the debugger report that the values correct? When does the debugger report that they go bad?
All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!
If I place a break point on that line I indicated, the debugger says <Bad Ptr> as soon as it stops there. If I press F10 to step on, it doesn't actually crash but I don't get a valid object either. I've got a feeling that the <Bad Ptr> message refers to the struct's 'id' field. The constants GTK_STOCK_APPLY / GTK_STOCK_CANCEL etc are simple #defines:-
I'm not yet sure if that's contributing to the problem somehow. Regarding instantiation, it's exactly as I described with these lines:-
Code:
// In a source file
const Gtk::BuiltinStockID APPLY = { GTK_STOCK_APPLY };
const Gtk::BuiltinStockID CANCEL = { GTK_STOCK_CANCEL };
const Gtk::BuiltinStockID OK = { GTK_STOCK_OK };
There's a whole bunch of such lines at the top of one of the library's source files. Nothing (within the library itself) seems to use any of the instantiated objects.
"A problem well stated is a problem half solved.” - Charles F. Kettering
If I place a break point on that line I indicated, the debugger says <Bad Ptr> as soon as it stops there. If I press F10 to step on, it doesn't actually crash but I don't get a valid object either. I've got a feeling that the <Bad Ptr> message refers to the struct's 'id' field. The constants GTK_STOCK_APPLY / GTK_STOCK_CANCEL etc are simple #defines:-
I'm not yet sure if that's contributing to the problem somehow. Regarding instantiation, it's exactly as I described with these lines:-
Code:
// In a source file
const Gtk::BuiltinStockID APPLY = { GTK_STOCK_APPLY };
const Gtk::BuiltinStockID CANCEL = { GTK_STOCK_CANCEL };
const Gtk::BuiltinStockID OK = { GTK_STOCK_OK };
There's a whole bunch of such lines at the top of one of the library's source files. Nothing (within the library itself) seems to use any of the instantiated objects.
Yes, but this is using the debugger on your code and finding that the pointer is bad. My idea was to use the debugger on the library code and check that the lines
etc are actually being executed within the library and if they are then to check within the libray code to make sure they are valid and then to trace through the library to fnd when the pointers become invalid. Is this instantiation code part of dllmain or some other initialisation routine? What causes these lines to be executed and when?
All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!
GTKMM_API is obviously _declspec(dllimport) (or export) as appropriate. It seems a bit unusual to use extern in addition GTKMM_API but the code won't compile if I try to exclude it. The actual instantiations are in one of the library's source files- e.g.
That's because these are variable declarations, not function declarations. If you omit the extern keyword, the variables are defined in any cpp file that includes this header, which will cause linker errors when included in more than one cpp file.
Regarding the <Bad Ptr> reported by the debugger, maybe that's just the debugger screwing up. Try to copy the value to a std::string and see what the value of the string is.
Cheers, D Drmmr
Please put [code][/code] tags around your code to preserve indentation and make it more readable.
As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky
Regarding the <Bad Ptr> reported by the debugger, maybe that's just the debugger screwing up. Try to copy the value to a std::string and see what the value of the string is.
Good suggestion but in fact that proved that the pointer address is indeed invalid (the program crashed when trying to assign whatever it's pointing to to a std::string).
Here's a theory... when the DLL was first linked, the value in (each) instance of BultinStockID::id would presumably have been set to the address of an appropriate string literal somewhere within the DLL. Is there any reason why BuiltinStockID::id would need to get changed / updated at run time? (cos presumably nothing's updating it??)
2nd theory... when the DLL gets loaded at run time, presumably something needs to initialise the addresses of any exported symbols. What if each structure is getting exported but not its 'id' member? It seems unlikely but is that possible?
"A problem well stated is a problem half solved.” - Charles F. Kettering
Third theory is that you forgot to put struct definitions to proper namespace, so there was nothing to export.
Oops... I forgot to show the namespaces in my example but in fact they are in the actual code
I built your sample Igor which is essentially identical to the original library code and it worked exactly as expected. I guess I'll need to look at the original VC project to see if there's some setting that's preventing it from working
"A problem well stated is a problem half solved.” - Charles F. Kettering
Then I can think only of one scenario that your library appears unloaded somehow to the moment of referencing.
A good theory - but some of the library's functions have already been called by the time this bit's needed.
There are A LOT of exported symbols in this DLL (over 13,000). Could that be exceeding some internal limit? The DLL itself isn't massive - just over 3.3Mb (Mb, not Gb) so that shouldn't be a factor...
"A problem well stated is a problem half solved.” - Charles F. Kettering
I built your sample Igor [...] and it worked exactly as expected. I guess I'll need to look at the original VC project to see if there's some setting that's preventing it from working
Arrrrrgh! Yes, it was a setting in the project (well, kinda). One of gtkmm's header files contains a flag which you set if you're building as a static library. When I first built gtkmm (about 3 years ago) I did indeed build it statically. I only converted it to a DLL a few weeks ago. But I'd totally forgotten about that flag (which was still #defined to 1). Now that I've set it correctly, everything works!! It's a bit weird really because everything compiled and linked and I could even call functions in the DLL - but it seems as if the static data objects just weren't getting initialised.
Thanks for all your suggestions guys - and especially for your sample code Igor. It was only when I saw your code working that it then occurred to me to suspect my project settings.
"A problem well stated is a problem half solved.” - Charles F. Kettering
Arrrrrgh! Yes, it was a setting in the project (well, kinda). One of gtkmm's header files contains a flag which you set if you're building as a static library. When I first built gtkmm (about 3 years ago) I did indeed build it statically. I only converted it to a DLL a few weeks ago. But I'd totally forgotten about that flag (which was still #defined to 1). Now that I've set it correctly, everything works!!
In general, whenever you get a single set of source files and those source files build both static library and DLL's, a preprocessor switch or switches must be set somewhere to build either the static library or DLL.
In addition, you should create two configurations, one for a DLL build and one for static lib build, where each configuration sets the appropriate switches.
I don't think this is a limit issue. If it were, you would never had it be successfully built. As for the other functions already called, that means nothing, as the library can be unloaded any moment later. Though this could be easily checked with VS, just put a breakpoint and inspect modules list.
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.