Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. caveats when exporting classes from a dll?

caveats when exporting classes from a dll?

Scheduled Pinned Locked Moved C / C++ / MFC
helpquestion
7 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • W Offline
    W Offline
    WernerP
    wrote on last edited by
    #1

    Hi, I am exporting classes from a dll, and I try to avoid recompiling the world, when the dll changes. I am feeling uncertain in that point and would greatly appreciate your advice. I reckoned the only problem would arise when classes with virtual functions would be used by the client. I set up a little experiment with 3 classes A, B and C, with 3 virtual functions each. C inherits from B and B from A. Found.. I can not change the order of virtual functions, nor can I insert one. The vftable entries seem to be permuted resp shifted by the number of insertions. I can insert additional code into a function, so that the function entries in the map file have shifted adresses. But still the client works without recompiling. I thought it would crash, why not does it? I thought this would result in wrong vftable entries. Are these not generated at dll compile time? These problems only seem occur when I use pointers to instances of these classes. I.e. as long as I do not pass any instance from a dll class via reference, or make a pointer to it, I will not have to recompile the client. True? Best regards Werner

    S C 2 Replies Last reply
    0
    • W WernerP

      Hi, I am exporting classes from a dll, and I try to avoid recompiling the world, when the dll changes. I am feeling uncertain in that point and would greatly appreciate your advice. I reckoned the only problem would arise when classes with virtual functions would be used by the client. I set up a little experiment with 3 classes A, B and C, with 3 virtual functions each. C inherits from B and B from A. Found.. I can not change the order of virtual functions, nor can I insert one. The vftable entries seem to be permuted resp shifted by the number of insertions. I can insert additional code into a function, so that the function entries in the map file have shifted adresses. But still the client works without recompiling. I thought it would crash, why not does it? I thought this would result in wrong vftable entries. Are these not generated at dll compile time? These problems only seem occur when I use pointers to instances of these classes. I.e. as long as I do not pass any instance from a dll class via reference, or make a pointer to it, I will not have to recompile the client. True? Best regards Werner

      S Offline
      S Offline
      Steen Krogsgaard
      wrote on last edited by
      #2

      First, I'm no expert on this, so I may be wrong. As I understand it you have three questions: 1: Why does your vtable still works although the functions in the dll have changed base adresses? 2: When are vtables generated? 3: How are dlls linked to the main app? 1: (actually ties in with two and three, but here goes) The vtable is populated at compile time. The main app calls the virtual function through the vtable, but reads the vtabel at runtime, not compile time. That's why it will work as long as the entries in the vtable doesn't change position. For instance, it's important that the adress of CYourClass::Foo is always the second entry in the vtable, but it's not important (at compile time) what the actual value of the second entry is. 2: at compile time. 3: When the app is started the dlls that it depends on are loaded (in theory, at least), and the entries into the dll are read from the export table. This is dynamic linking, where the function calls are resolved at runtime. Even though your statically link to your dll Windows will still dynamically link the dll - all the LoadLibrary and GetProcAddress calls are just done behind the scenes. So, as long as the app can find the right entries in the table the dll will work. Why it doesn't work with function pointers is a little more unclear to me, but that will of course depend on how you construct and use the pointers. Cheers Steen. "To claim that computer games influence children is ridiculous. If Pacman had influenced children born in the 80'ies we would see a lot of youngsters running around in dark rooms eating pills while listening to monotonous music"

      W 1 Reply Last reply
      0
      • S Steen Krogsgaard

        First, I'm no expert on this, so I may be wrong. As I understand it you have three questions: 1: Why does your vtable still works although the functions in the dll have changed base adresses? 2: When are vtables generated? 3: How are dlls linked to the main app? 1: (actually ties in with two and three, but here goes) The vtable is populated at compile time. The main app calls the virtual function through the vtable, but reads the vtabel at runtime, not compile time. That's why it will work as long as the entries in the vtable doesn't change position. For instance, it's important that the adress of CYourClass::Foo is always the second entry in the vtable, but it's not important (at compile time) what the actual value of the second entry is. 2: at compile time. 3: When the app is started the dlls that it depends on are loaded (in theory, at least), and the entries into the dll are read from the export table. This is dynamic linking, where the function calls are resolved at runtime. Even though your statically link to your dll Windows will still dynamically link the dll - all the LoadLibrary and GetProcAddress calls are just done behind the scenes. So, as long as the app can find the right entries in the table the dll will work. Why it doesn't work with function pointers is a little more unclear to me, but that will of course depend on how you construct and use the pointers. Cheers Steen. "To claim that computer games influence children is ridiculous. If Pacman had influenced children born in the 80'ies we would see a lot of youngsters running around in dark rooms eating pills while listening to monotonous music"

        W Offline
        W Offline
        WernerP
        wrote on last edited by
        #3

        Thank you! The vtable is populated at compile time. The main app calls the virtual function through the vtable, but reads the vtabel at runtime, not compile time. > => when I insert a virtual function or change its position, the the client will read a wrong function address instead of the original one, if it does use the vtable. Why it doesn't work with function pointers is a little more unclear to me, but that will of course depend on how you construct and use the pointers. > you gave the answer. When I use a class from a dll this way MyDllClass theClass; theClass.aVirtualFunc(); // the vtable will not be used when calling this function (right?). It's clear, to which class aVirtualFunc refers, it can be referred to by it's export name or ordinal. But here MyDllBaseClass * ptheClass = new(MyDllClass); ptheClass->aVirtualFunc(); // the vtable will be used. Beware of changing the functions position in the dll without recompiling the client. The wrong function will be used (it happened also when I used a MyDllClass * instead of MyDllBaseClass *). or even here, I think - and less obvious - MyDllClass theClass; doSomethingWith(theClass); .. void doSomethingWith(MyDllClass & refToMyClass) {.. // because there is an implicit pointer operation. . Cheers Werner

        S 1 Reply Last reply
        0
        • W WernerP

          Hi, I am exporting classes from a dll, and I try to avoid recompiling the world, when the dll changes. I am feeling uncertain in that point and would greatly appreciate your advice. I reckoned the only problem would arise when classes with virtual functions would be used by the client. I set up a little experiment with 3 classes A, B and C, with 3 virtual functions each. C inherits from B and B from A. Found.. I can not change the order of virtual functions, nor can I insert one. The vftable entries seem to be permuted resp shifted by the number of insertions. I can insert additional code into a function, so that the function entries in the map file have shifted adresses. But still the client works without recompiling. I thought it would crash, why not does it? I thought this would result in wrong vftable entries. Are these not generated at dll compile time? These problems only seem occur when I use pointers to instances of these classes. I.e. as long as I do not pass any instance from a dll class via reference, or make a pointer to it, I will not have to recompile the client. True? Best regards Werner

          C Offline
          C Offline
          cmk
          wrote on last edited by
          #4

          A dll has functions exported by ordinal, and (optionally) name. When you create a dll you have 2 ways of exporting data/functions: 1. use an export file Here you explicitly define the ordinal (and optionally hide the name) of the functions to be exported. Because you control the ordinal you control any changes that occur between releases. Usually when new functions are added you just assign them new (unused) ordinal values. Class methods are exported using their mangled names, which makes this a tedious way of exporting class' by hand, usually you will have another program generate this file. 2. use __declspec(dllexport) Here the compiler auto-generates the export table from all __declspec(dllexport) it finds. You have no control over the ordinals assigned to data/functions. I assume you are using __declspec(dllexport) statements. What you are talking about is observing an effect and inferring a reason. You can NOT assume your conclusions will hold for all cases - they won't. To get the result you want you need to use an export file. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_core_export_functions_from_a_dll_by_ordinal_rather_than_by_name.asp[^] ...cmk Save the whales - collect the whole set

          W 1 Reply Last reply
          0
          • W WernerP

            Thank you! The vtable is populated at compile time. The main app calls the virtual function through the vtable, but reads the vtabel at runtime, not compile time. > => when I insert a virtual function or change its position, the the client will read a wrong function address instead of the original one, if it does use the vtable. Why it doesn't work with function pointers is a little more unclear to me, but that will of course depend on how you construct and use the pointers. > you gave the answer. When I use a class from a dll this way MyDllClass theClass; theClass.aVirtualFunc(); // the vtable will not be used when calling this function (right?). It's clear, to which class aVirtualFunc refers, it can be referred to by it's export name or ordinal. But here MyDllBaseClass * ptheClass = new(MyDllClass); ptheClass->aVirtualFunc(); // the vtable will be used. Beware of changing the functions position in the dll without recompiling the client. The wrong function will be used (it happened also when I used a MyDllClass * instead of MyDllBaseClass *). or even here, I think - and less obvious - MyDllClass theClass; doSomethingWith(theClass); .. void doSomethingWith(MyDllClass & refToMyClass) {.. // because there is an implicit pointer operation. . Cheers Werner

            S Offline
            S Offline
            Steen Krogsgaard
            wrote on last edited by
            #5

            WernerP wrote:

            MyDllClass theClass; theClass.aVirtualFunc(); // the vtable will not be used when calling this function (right?). It's clear, to which class aVirtualFunc refers, it can be referred to by it's export name or ordinal.

            I think the vtable will be used regardless of whether you use . or ->, but it may be implementation-specific. In any regard, you shouldn't count on it. As cmk wrote, you have no control of the ordinals assigned to the exported functions when you use __declspec(dllexport). So the safest option is to recompile. Anyway, if you headers doesn't change it's only relinking which is pretty fast. If your headers change you need to recompile anyway. Cheers Steen. "To claim that computer games influence children is ridiculous. If Pacman had influenced children born in the 80'ies we would see a lot of youngsters running around in dark rooms eating pills while listening to monotonous music"

            1 Reply Last reply
            0
            • C cmk

              A dll has functions exported by ordinal, and (optionally) name. When you create a dll you have 2 ways of exporting data/functions: 1. use an export file Here you explicitly define the ordinal (and optionally hide the name) of the functions to be exported. Because you control the ordinal you control any changes that occur between releases. Usually when new functions are added you just assign them new (unused) ordinal values. Class methods are exported using their mangled names, which makes this a tedious way of exporting class' by hand, usually you will have another program generate this file. 2. use __declspec(dllexport) Here the compiler auto-generates the export table from all __declspec(dllexport) it finds. You have no control over the ordinals assigned to data/functions. I assume you are using __declspec(dllexport) statements. What you are talking about is observing an effect and inferring a reason. You can NOT assume your conclusions will hold for all cases - they won't. To get the result you want you need to use an export file. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_core_export_functions_from_a_dll_by_ordinal_rather_than_by_name.asp[^] ...cmk Save the whales - collect the whole set

              W Offline
              W Offline
              WernerP
              wrote on last edited by
              #6

              Thanks. Option 1 is tedious indeed. I have been looking for ways how to generate a def file with mangled names, they talk about using (1) the VC++ /FAcs compiler option to get a listing (2) the VC++ generate map file option when linking (3) the DUMPBIN.EXE on the dll to get the mangled names. There is also a tool from http://www.objmedia.demon.co.uk/freeSoftware/def32.html[^] which creates a def file from the map file and also assigns ordinals to it. The result looks ok (but haven't yet tested compiling and linking). regards Werner

              C 1 Reply Last reply
              0
              • W WernerP

                Thanks. Option 1 is tedious indeed. I have been looking for ways how to generate a def file with mangled names, they talk about using (1) the VC++ /FAcs compiler option to get a listing (2) the VC++ generate map file option when linking (3) the DUMPBIN.EXE on the dll to get the mangled names. There is also a tool from http://www.objmedia.demon.co.uk/freeSoftware/def32.html[^] which creates a def file from the map file and also assigns ordinals to it. The result looks ok (but haven't yet tested compiling and linking). regards Werner

                C Offline
                C Offline
                cmk
                wrote on last edited by
                #7

                The ObjMedia tool looks promising. ...cmk Save the whales - collect the whole set

                1 Reply Last reply
                0
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • World
                • Users
                • Groups