Exporting a struct from a DLL
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.
Code:
// In the header file:-
namespace Gtk
{
struct BuiltinStockID
{
const char* id;
};
namespace Stock
{
extern GTKMM_API const Gtk::BuiltinStockID APPLY; /* @image gtk-apply.png */
extern GTKMM_API const Gtk::BuiltinStockID CANCEL; /* @image gtk-cancel.png */
extern GTKMM_API const Gtk::BuiltinStockID OK; /* @image gtk-ok.png */
}
}
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:-
Code:
Gtk::BuiltinStockID MyStockID;
MyStockID = Gtk::Stock::CANCEL; // <--- debugger reports <Bad Ptr>
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 :confused:
Re: Exporting a struct from a DLL
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?
Re: Exporting a struct from a DLL
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:-
Code:
#define GTK_STOCK_APPLY "gtk-apply"
#define GTK_STOCK_CANCEL "gtk-cancel"
#define GTK_STOCK_OK "gtk-ok"
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.
Re: Exporting a struct from a DLL
Quote:
Originally Posted by
John E
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.
Re: Exporting a struct from a DLL
Quote:
Originally Posted by
D_Drmmr
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?
Re: Exporting a struct from a DLL
Quote:
Originally Posted by
John E
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:-
Code:
#define GTK_STOCK_APPLY "gtk-apply"
#define GTK_STOCK_CANCEL "gtk-cancel"
#define GTK_STOCK_OK "gtk-ok"
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
Code:
const Gtk::BuiltinStockID APPLY = { GTK_STOCK_APPLY };
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?
1 Attachment(s)
Re: Exporting a struct from a DLL
Third theory is that you forgot to put struct definitions to proper namespace, so there was nothing to export.
Code:
#include "98dll.h"
#define GTK_STOCK_APPLY "gtk-apply"
#define GTK_STOCK_CANCEL "gtk-cancel"
#define GTK_STOCK_OK "gtk-ok"
namespace Gtk { namespace Stock {
const Gtk::BuiltinStockID APPLY = { GTK_STOCK_APPLY };
const Gtk::BuiltinStockID CANCEL = { GTK_STOCK_CANCEL };
const Gtk::BuiltinStockID OK = { GTK_STOCK_OK };
}}
I always check if everything exported as expected. Please see the sample.
Re: Exporting a struct from a DLL
Quote:
Originally Posted by
Igor Vartanov
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 :blush:
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 :(
Re: Exporting a struct from a DLL
Quote:
Originally Posted by
John E
I forgot to show the namespaces in my example but in fact they are in the actual code
Then I can think only of one scenario that your library appears unloaded somehow to the moment of referencing.
Re: Exporting a struct from a DLL
Quote:
Originally Posted by
Igor Vartanov
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... :confused:
Re: Exporting a struct from a DLL
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.
Re: Exporting a struct from a DLL
Quote:
Originally Posted by
John E
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. :thumb:
Re: Exporting a struct from a DLL
Quote:
Originally Posted by
John E
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.
Regards,
Paul McKenzie
Re: Exporting a struct from a DLL
Quote:
Originally Posted by
John E
Thanks for all your suggestions guys - and especially for your sample code Igor.
Well, in fact it was your sample code. I just put all the pieces together and made sure it really works. You might do the same thing any time before. :)