Solved

DLL [ Drill ]

Posted on 2001-08-22
62
601 Views
Last Modified: 2008-02-01
Hello Everyone! I had few doubts on explicity calling a DLL.
I have written a simple DLL Client that uses LoadLibrary to load the DLL and then gets the function address via GetProcAddress. Finally it tries calling the function.
This is what I get an error when it tries calling the func
--------------------------------
The Value of ESP Was not properly saved across function call. This is usually a result of calling function declared with one calling convention with a function pointer declared with a different calling convention.
--------------------------------
I used implict method for calling the DLL that is by including the Lib and .h in my project and then declaring the object for the DLL and it worked.

Can someone point out whats my bug???
TIA

=============
DLL Client Code
#include <stdio.h>
#include <windows.h>

//#include ".\\..\\TestDLL\\TestDLL.h"

/* Works good
void main()
{
     cMyDLL obj;
     
     int result,a=9,b=10;
     
     result=obj.Sum(a,b);
     
     printf("Result via call to the DLL %d\n",result);

}
*/    

//*
typedef int (*PFNSUM)(int,int);
 
VOID main(VOID)
{
    HINSTANCE hinstLib;
    PFNSUM pfnSum;
    BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
 
    // Get a handle to the DLL module.
     hinstLib = LoadLibrary("TestDLL");
         
      int result,a=9,b=10;
 
// If the handle is valid, try to get the function address.
     if (hinstLib != NULL)
     {
      pfnSum=(PFNSUM)GetProcAddress(hinstLib, "Sum");
           
         // If the function address is valid, call the function.
         if (fRunTimeLinkSuccess = (pfnSum!= NULL))
           {
                result=pfnSum(a,b); //fails right here
                printf("Result via call to the DLL %d\n",result);
           }
 
        // Free the DLL module.
 
        fFreeResult = FreeLibrary(hinstLib);
    }
 
    // If unable to call the DLL function, use an alternative.
    if (! fRunTimeLinkSuccess)
        printf("message via alternative method\n");

}
/*******************************************************/
DLL Code
// ------- Header File TestDLL.h ------
#pragma once

#include <stdio.h>
class cMyDLL
{
public:

     cMyDLL(){}
     ~cMyDLL(){}
     int Sum(int a,int b);

};
// ---- TestDLL.cpp ------
#include "TestDLL.h"
int cMyDLL::Sum(int a,int b)
{
     return a+b;
}

// ---- DEF File for Exporting the Sybmols
// TestDLL.def
LIBRARY TestDLL

EXPORTS
 Sum   @1
0
Comment
Question by:mettlus
  • 22
  • 22
  • 7
  • +3
62 Comments
 
LVL 1

Expert Comment

by:AlexReser
ID: 6416482
Your function Sum is a class member.
You try to call a non-class member function Sum - of course, you get an error.

I think, you can not use your DLL for calling class member function via LoadLibrary.
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6416632
try this:

typedef int (CALLBACK *PFNSUM)(int,int);
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6417644
You need to either move the "Sum" function out of the class, and call it like a "normal" function, or you would need to export the "cMyDLL" class from the DLL, and then create an instance of "cMyDLL", and call "Sum" from it.

Making "Sum" a static member function might make a difference, though.  You might be able to get away with doing it that way, but it is a bit kludgy.

[
MichaelS, why would that make a difference?  The "Sum" function would still expect an implicit/hidden "this" pointer to be on the stack, which is why the poster is getting a stack error in the first place.  Changing the calling convention would not magically make the "this" parameter appear...
]

-=- James.
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6417657
>MichaelS, why would that make a difference?  
coz in my case it was helpful. it wosn't a member function but it was the same error.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6417796
I see.  In your case, it was a calling-convention problem, but not so here.

-=- James.
0
 
LVL 6

Accepted Solution

by:
MichaelS earned 100 total points
ID: 6417927
To jtwine,

I specially created two projects and did copy/paste code from mettlus to it. Also added my correction. Works without any problems. VC++ 6.0 w2k.

when I removed CALLBACK I got the same error as mettlus.
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6417932
To jtwine again. Please don't clame someone is wrong if you are not sure in that.
0
 

Author Comment

by:mettlus
ID: 6418339
Thx for the feedback. Isn't ther a way by which I can export the whole Class using .def file?
I know in VC++ if you let wizard create a DLL Project that exports some symbols, your whole class is exported.

>>I think, you can not use your DLL for calling class >>member function via LoadLibrary
Can you please tell me whats the ideal use of LoadLibrary then?

Thanks

0
 

Author Comment

by:mettlus
ID: 6418350
MichaelS is the MAN!!!!!!!!!!!!!! It worked the moment I used the new definition of the Function Pointer using "callback". Dear Michael, can you please tell me whats the Magic of Keyword CALLBACK (making the whole thing work!)

Thxs a lot
0
 

Author Comment

by:mettlus
ID: 6418570
MichaelS is the MAN!!!!!!!!!!!!!! It worked the moment I used the new definition of the Function Pointer using "callback". Dear Michael, can you please tell me whats the Magic of Keyword CALLBACK (making the whole thing work!)

Thxs a lot
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6419894
> Isn't ther a way by which I can export the whole Class using .def file?

I am not sure.  I believe that you need to put the __declspec( dllexport ) directive in front of the class def. in order for it to work correctly.

[
MichaelS, please try this with your test example...  Add a data member to the class you are using.  Initialize it to a known value (like 2) and then try to access (read) it from the class' member function.  I believe that you will find the results interesting.  If you do not find them interesting, please make your test code available.
]

0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6419896
Even better: take a look at what the "this" poiner value is while inside the function.

-=- James.
0
 

Author Comment

by:mettlus
ID: 6419921
Hey Michael/Or anyone else, can you please elaborate whats the magic of putting CALLBACK keyword made my DLLClient easily call the DLL function via the LoadLibrary Method!!

I will post the points shortly.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6419950
Placing CALLBACK in the typedef for the function pointer changes the "calling convention" for the function.  The "calling convention" includes how a function is called, returned from, and how it's parameters (if any) are arranged on the stack, in registers, or both.  

Parameters are pushed onto the stack in a certain order.  In order for a function to correctly pop these parameters off in the right order, it needs to know the order in which they were pushed into the stack.  That is where the calling convention comes in.

Also, the calling convention can have an effect on the name mangling (or decoration) of method names.

-=- James.

0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6420241
(Sorry, I missed that you asked why CALLBACK seems to work for you.)

Basically, you are getting lucky: A "this" pointer is still expected, but is not really used by member methods unless member variables (or possibly the vtable, but not likely, depends on implementation of vtables) are accessed by the code.

C++ classes work like this: one copy of the code, and as many copies of the data as necessary.  The data is referenced through the implicit "this" pointer, which is implicitly passed to each non-static method of a class.  

The reason you code works is because the method is not trying to access any member variables, or anything else that requires a "this" pointer, like calling another of the class' methods that may use member variables.  The change to the calling convention "hides" the problem of trying to call a non-static class method directly.

This can be evidenced by trying to access an initialized member variable in the Sum method, and seeing that the value of the variable is not what is expected, and will likely crash when read from and/or written to.

-=- James.
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6421151
>Hey Michael/Or anyone else, can you please elaborate whats the magic of putting CALLBACK keyword made
my DLLClient easily call the DLL function via the LoadLibrary Method!!

from the headers you can see that
#define CALLBACK __stdcall

and when you created your class and exported a function you also used __stdcall.




>The reason you code works is because the method is not trying to access any member variables, or anything
else that requires a "this" pointer, like calling another of the class' methods that may use member
variables.  The change to the calling convention "hides" the problem of trying to call a non-static
class method directly.

Somehow this question is going to long discussion or what "this" means and why you can't use "this" in non static member functions. BUT, as I see the question actually is "Can someone point out whats my bug???" and for me it sounds like "what I have to chage to get it works?" and not like "how to write it better, faster more correctly or what ever". Second one is completely different question. It's more like "how to export member function from dll".
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6421716
> BUT, as I see the question actually is "Can someone point out whats
> my bug???" and for me it sounds like "what I have to chage to get it works?"

But the bug is two-fold.  First, (s)he is trying to access a class' (non-static) member function without creating an instance of the class itself.  Anyone that has any real experience in C++ with trip on that.

> and not like "how to write it better, faster more correctly or what ever".

It is not a matter of better, or faster; but it is about doing things right!  (With more experience, people with learn that.)  I have to guess that you did not try out what I suggested, or you would not have made your last post.  

Simple Fact: Both of you are getting *lucky* with that solution.  Eventually, that solution will be tried in a real-world non-trivial situation, and will behave in strange manner, and may or may not crash at odd times.  (Try out what I suggested and you will see what I mean.)

> It's more like "how to export member function from dll".

In order to export a (non-static) member function, you need to fully understand how C++ member functions work internally, what a "this" pointer is, how a member function gets a "this" pointer.  If you do not know those things, you are out of your league, and should not be responding as an "expert" on this manner.

-=- James.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6421930
For further evidence of this problem (which is rampant in the software world: witness Java), I refer you to: http://www.apa.org/journals/psp/psp7761121.html

-=- James.
0
 

Author Comment

by:mettlus
ID: 6422118
Dear James, Thx a lot for pointing out a serious flaw in the code. I would appreciate if you can suggest me the ideal solution to my code. How should I write the DLL and how should a client call the DLL?
I know a way in which u basically include the .lib and .h in ur proj workspace, place the DLL in the system32 directory. And then use the DLL as it was just another class in ur project (by instantiation an object and thereafter calling the methods...)
I would also love to hear why LoadLibrary was made and how it became so popular?
Thx and lot of appreciation to ALL OF YOU GUYS
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6422150
jtwine,
I am 100% agree with you and I was agree from the begining BUT  


>This is what I get an error when it tries calling the func
--------------------------------
>The Value of ESP Was not properly saved across function call. This is usually a result of calling function
declared with one calling convention with a function pointer declared with a different calling convention.

I just corrected the place in the code which produced THIS error. What's wrong with you??????
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6422410
>I would also love to hear why LoadLibrary was made and how it became so popular?

>How should I write the DLL and how should a client call the DLL?

Sounds like two new questions :(((((
And what's about original one?
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6422428
mettlus, I checked your profile and now I see that you just don't like to give you points away
0
 

Author Comment

by:mettlus
ID: 6422726
Sorry in the past had few blow ups!!! I am not like that.

Sincere apologies for the delay in giving points
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6422906
> I just corrected the place in the code which produced THIS error. What's wrong with you??????

Because you did NOT correct the code, you made a CHANGE that hides the underlying problem with the code: the poster is trying to access a non-static method of a class WITHOUT instantiating the class itself.

If you know ANYTHING about C++, you know that all of a class' non-static methods get a hidden "this" pointer passed to them.  The function that the poster is trying to access is still going to try get that "this" pointer, despite a seemingly empty parameter list.

Your change hid the obvious problem, but the underlying problem is still there.  When tried on any non-trivial piece of code, it *will* fail, possibly at random.  That is price you pay for not knowing everything that you should know, but thinking that you do.  That is why it is not a "fix": a "fix" fixes a problem, it does not hide it.  

If you do not believe me, research it, ask others, THEN post commentary.

As you seem to be unwilling to try out the change to the example that I suggested (or unwilling to report what happened when you did), you are demonstrating one of the properties mentioned in the article that I posted the link to above.  Nothing that can be done about that, I guess.

And that is what is RIGHT with me: I have the knowledge and experience to call myself an "expert", and can back it up with ease.

>I would also love to hear why LoadLibrary was made and how it became so popular?

    LoadLibrary is the function used to map a DLL into your process' address space.  DLLs were an idea that can help reduce the size of an executable by placing common code into the DLL, and not building it into every single application.

>How should I write the DLL and how should a client call the DLL?

   Either create standard/normal functions and export them from the DLL, or export the class from the DLL, create an instance of it, and then access it's member functions.

   Oh, and ignore those that are point-hungry on this site: many believe that the points they have indicate how good they are, instead of the fact that it just means someone (who might not know any better) accepted their answer.

-=- James.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6422910
> To jtwine again. Please don't clame someone is wrong if you are not sure in that.

Have no doubts, I am sure.  Are you?

-=- James.
0
 

Author Comment

by:mettlus
ID: 6424604
Thx a lot James, you really have in-depth knowledge.


Thx Again to all of you
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6427794
>Thx a lot James, you really have in-depth knowledge.

I think you meant that James has more deper knowladge than you :)

>Have no doubts, I am sure.  Are you?

Yes, I am sure. This is absolutele correct code and I didn't "made a CHANGE that hides the underlying problem with the code". What I did is just correcting the code which was not working. Who did tell you that it's not right or not possible to use non static functions???????

What is so wrong with that? If you have a function, you can export it from dll and than you can call it? Sure, if in the future mettlus will start to use "this" than he is in problems. Till he doesn't use it EVRYTHING is OOOOKKKKK, evrything is 100% correct. There is a function, there is a call to that function and evrything works correctly not becous it's a luck, becouse it's 100% correct function and 100% correct call to that function.

Now, jtwine, I am stopping this stupid discussion about your ambitions.

Good luck to evrybody.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6428792
> This is absolutele correct code and I didn't "made a CHANGE that hides the underlying problem with the code".

   Once again, I can see that you did not try the changes as I instructed.  (This is one of the traits of the unskilled: they cannot recognize competence in others, and therefore assume others are wrong.)

   Since you will not take the actions required to understand why the code is not correct, you remain confused.  Since you seem to not want to know *why* your change is incorrect, that speaks volumes about your technical acumen (or lack of).

> Who did tell you that it's not right or not possible to use non static functions???????

   It is not correct to call non-static functions without an using instance of the class they are contained in.  Non-static functions expect a "hidden" this pointer in their parameter list.  There is NO PLACE in your change that causes anything even close to an instance of the class to be created.  As I said, if you would have TRIED the changes that I suggested, you would SEE why the CHANGE is not a fix.  

I am not saying that your change *seems* to work.  Filling the radiator in your car with pure water will seem to work for a while, too, but eventually will freeze or boil over.

In normal C++ code, you have to instantiate an object before using any of it's non-static methods or data members, right?  Why the HELL would you think that it would be different when trying to access that same function in a DLL?

> Sure, if in the future mettlus will start to use "this" than he is in problems.

mettlus does not have to use the "this" pointer directly, the function may use it without his/her knowing (if you understood how C++ classes work, you would know that).  And therein lies the problem: since you do not know how member methods work, you likely lack the skills to know how to call them correctly, and the metacognitive skills to understand why your change is inappropriate.

> Till he doesn't use it EVRYTHING is OOOOKKKKK, evrything is 100% correct.

   Yes, everything *seems to work correctly* to the unskilled.  That does not mean that your fix is OK, or correct.  You can also drive to work going 5 MPH on a highway that is moving at 65MPH.  You will get there, but it is *not* OK nor correct (nor safe) to do so.

> There is a function, there is a call to that function and evrything works correctly not becous it's a luck,
> becouse it's 100% correct function and 100% correct call to that function.

   That is not your everyday "function".  Normal functions only expect the parameters that you declare inside the function's parens.  A class' non-static member function expects the number of parameters you declare PLUS 1.  So a member method with NO PARAMETERS still expects one parameter to be there.  That is where your change breaks down: there is still a missing parameter.

   You continue to believe that your change is a fix, but will not back it up with the technical reasoning why.  I, on the other hand, am giving you the chance to learn, but you continue to believe that you are correct.  (Yet another trait of the unskilled: they cannot recognize their own incompetence.)

> Now, jtwine, I am stopping this stupid discussion about your ambitions.

   My ambitions are of such things that you could not comprehend.  Do not get in over your head.  

   But do not fret: eventually, you will become more skilled and/or experienced, will actually learn about the things you are working with, look back on this topic, and will see the mistakes you have made through hindsight (and hindsight is often the late application of should have been common sense).

-=- James.  
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6428859
I promised do not reply any more BUT I just can't ignore it.

>It is not correct to call non-static functions without an using instance of the class they are contained
in.

It is correct, 100% correct. Static or non static function has a body and it doesn't metter is there an instance of class or not. You can call it without any problem.

If I will follow your logic than it's not correct to use functions at all cos if you will make that function a member function and than if you will insert some code which uses "this" than you will have a problems. Ha-ha-haaaaa-haaaaa. In such a logic it's not correct to write programs at all cos you can modify it in the way it will crush and it means your program was incorrect from beginning.

>I am not saying that your change *seems* to work.  

My changes not "seems" to work, my changes works and 100% correct. There is a function, it has a body and it can be called. Sure, if the function has something to do with member variables than it ISN'T correct, but if there is no class related stuff than it's 100% correct.

>since you do not know how member methods work, you likely lack the skills to know how to call them correctly,
and the metacognitive skills to understand why your change is inappropriate

I think "you do not know how member methods work" cos you say it's not correct. What is the difference in the following code and why second sample is not correct?

first:
int a(int i)
{    return i++;
}

main()
{   return a(5);
}

second:
class Sample
{    public:
         int a(int i)
         {    return i++;
         }
};

main()
{    return Sample::a(5);
}
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6428955
Ok, sample is not correct cos we are talking about using not standart technique, so to be exactly at the point where we started the second sample sould be:


typedef int(CALLBACK *PFNA)(int);
main()
{    PFNA pfna = (PFNA)GetProcAddress(NULL, "a");
     return pfna(5);
}
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6428970
> It is correct, 100% correct. Static or non static function has a body and it doesn't metter is there
> an instance of class or not. You can call it without any problem.

You are making the assumption that just because you CAN do something, you SHOULD do something.  And, yes, it does matter for non-static function members.  ONCE AGAIN, I can see that you did not try the changes that I suggested.

> If I will follow your logic than it's not correct to use functions at all [...]

You followed the logic incorrectly.  Try again.  And, since the sentence is not written correctly, I cannot be sure what you mean.  Rather than make incorrect assumptions about what you wrote, just rewrite it correctly.  Oh, and it is "crash", not "crush".

> My changes not "seems" to work, my changes works and 100% correct. There is a function, it has a body
> and it can be called. Sure, if the function has something to do with member variables than it ISN'T
> correct, but if there is no class related stuff than it's 100% correct.

Your change works, but it is not correct.  But the function HAS "class related stuff": It is a member method!  A member of a CLASS, hence it has class stuff.  The function does not have to access a member variable directly: it could call another method that does, or even try to make a call to a virtual function, which would fail horribly.

BTW: The problem with your second example is that you are trying to call a non-static method without creating an instance of the class the function is contained in.  Change it to a static method, and it will work.  Non-static methods need a "this" pointer.  You normally use an instance of a class to provide the "this" pointer.  And since it is not supposed to work, you should not be getting around that error by placing the class into a DLL and calling it directly.

-=- James.
0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 
LVL 4

Expert Comment

by:jtwine100697
ID: 6428999
The call to GetProcAddress(...) will fail because "Sample::a" is not exported directly (with an undecorated name of "a", BTW).  But I can see where you are trying to go with this: If it is exported, then yes, you CAN call the function, BUT IT IS STILL NOT CORRECT TO DO SO!  Just because you CAN does not mean that you SHOULD.

By doing do, you are getting around the compiler trying to stop you from doing something wrong: directly accessing a non-static member of a class without a valid instance of the class (a "this" pointer).

-=- James.
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6429012
>ONCE AGAIN, I can see that you did not try the
changes that I suggested.

I know what happens if you use "this" in such sample that's why I am sure it's 100% correct.

>Oh, and it is "crash", not "crush".
Nice argument :) May be you are in a wrong TA? If you don't know than I can tell you that there is a difference between C++ language and "english".

>The function does not have to access a member
variable directly: it could call another method that does, or even try to make a call to a virtual function,
which would fail horribly.

As we see from sample is does NOT "call another method". And specially for you, jtwine, I did compiled those two samples and checked Dissasambly window. Results is here:

first:
push        5
call        @ILT+5(a) (0040100a)

second:
push        5
call        dword ptr [ebp-4]
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6429033
>The call to GetProcAddress(...) will fail

it isn't, sorry. I compiled it and check it. works 100% OK.

>Just because you CAN does not mean that you SHOULD

As I remember the discussion was CAN you do it or NOT. Is it correct or not correct. Than what it the meaning of "correct"?

>By doing do, you are getting around the compiler trying to stop you from doing something wrong: directly
accessing a non-static member of a class without a valid instance of the class (a "this" pointer).

this is not wrong, this is just not standard and can be place where problems starts if "you don't know exactly what are you doing". If you KNOW how it works inside than it's not a problem.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6429096
> I know what happens if you use "this" in such sample that's why I am sure it's 100% correct.

Then you should also know that telling a lesser skilled person that "this is the way to do it" WITHOUT explaining that you are "getting around" the problem is incorrect.  

> I can tell you that there is a difference between C++ language and "english".

And if you research the history of software development, you will see that the term is "crash", not "crush".  Again, do not get in over your head here.

> As we see from sample is does NOT "call another method".

Re-read my posts: I never said it did.  However, I DID day that you change will fail in any non-trivial situation.  And it will.

> And specially for you, jtwine, I did compiled those two samples and checked Dissasambly window.

   Take another look at the generated assembly code: You will see that as the stack frame is set up for the method function, it tries to access three paremeters, "a", "b", and "this".  Also, if you have a valid pointer to some memory last on your stack before calling a method that tries to set some member variables, for example, it might not crash, but will cause memory corruption that might not be noticed for some time.

> > The call to GetProcAddress(...) will fail
>
> it isn't, sorry. I compiled it and check it. works 100% OK.

It will compile.  But at runtime, it will fail to find the function unless it is exported.  Your project settings and/or DEF file can specify to export the class and function.  But the code you posted does not do that.  Hence, no finding the exported function.  IME, you need a DEF file to export a function with an undecorated name.

> As I remember the discussion was CAN you do it or NOT.
> Is it correct or not correct. Than what it the meaning of "correct"?

[From the original poster: "Can someone point out whats my bug???"]

The poster asks what the bug is: the bug is that (s)he was trying to access a non-static member function without creating an instance of the class.  Your CHANGE got around the problem, and worked, yes, but only for trivial examples such as the one originally posted.  

The FIX is to either make the function a "normal" function, or make it a non-static method, or instantiate an instance of the class, like the original working code did!

> this is not wrong, this is just not standard [...]

Non-standard is doing things like using the Microsoft extensions to the C++ language.  Things that normally cause errors are wrong, not non-standard.

> and can be place where problems starts if "you don't
> know exactly what are you doing". If you KNOW how it
> works inside than it's not a problem.

And the original poster does not know exactly what they are doing.  That was made evident by the post itself.  What you have done is given the poster a solution, when they do not understand, and can later use even more incorrectly than now.  And, due to the nature of DLLs, you quite often do NOT know what is inside the DLL.

-=- James.
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6429132
OK, I am tired. You win, I was 100% wrong. Will post points for you cos my solution is "wrong" as you said.I don't like to discuss it any more. Better to help some one who need it. You right, I am wrong. Post here your solution for mettlus (he has only mine right now) and you will get points from me.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6429170
You are missing the point: You are not 100% wrong.  Your change is not entirely 100% correct.  Offering such as change AS a 100% correct solution, however, is wrong.

mettlus already has seen my suggestions in my posts, and hopefully, has implemented one of them already.

> I don't like to discuss it any more

Then *research* it, do not discuss it.

> Will post points for you [...]

I do not want your points, or anyone else's for that matter: I am not judged by my peers or superiors by such trivial things as numbers.  We are a bit smarter and more experienced than that.  But thank you anyway.

(BTW: LMK when you check up on "crush" .vs. "crash", and exporting undecorated names...)

-=- James.
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6429515
>(BTW: LMK when you check up on "crush" .vs. "crash", and exporting undecorated names...)

Actually english is not my native language and it's hard to be right in spelling for me.

About points, this site is about helping people and get points for that. Personaly I fills pissed when I help someone and had nothing for that.

Any way look for points for you in this TA. And it also was kind of pleasure for me to disscuss it.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6429665
Alright, mettlus...

PAY UP! :)

MichaelS, I will give you points if mettlus does not... :P

-=- James.
0
 

Expert Comment

by:simon_capewell
ID: 6431999
Something nobody seems to have mentioned is that MichaelS suggested the use of CALLBACK as the calling convention on the function pointer. Since the function isn't exported from the dll as CALLBACK there is a mismatch in calling conventions.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6432099
Right, which is why I said to him/her:

"I see.  In your case, it was a calling-convention problem, but not so here."

-And is why I argue that his/her "change" is not a "fix".  

Also, IIRC, the class' member function will actually have a calling convention of "__thiscall".  Which you cannot use directly (meaning, you cannot typedef a function opointer as "__thiscall"), and for good reason.

-=- James.
0
 

Expert Comment

by:simon_capewell
ID: 6432121
Exactly, it's a bodge that just happens to work because the this pointer happens to not be used by the member function.
0
 
LVL 3

Expert Comment

by:modder
ID: 6435398
As requested. I have reduced the points to zero as the accepted answer appears to be incorrect.

modder
Community Support
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6435547
>As requested. I have reduced the points to zero as the accepted answer appears to be incorrect.

What?????

Hey, people, are you crazy? Why answer is incorrect?

>that just happens to work because the this pointer happens to not be used by the
member function.

and so what? is it not allowed that member function doesn't uses "this"?????

What is incorrect? Calling the function which doesn't use "this"? Using "GetProcAddress" or exporting a member function of the class? What? From time to time I just love this site more and more. Looks like it's really time to looking for something more professional.
0
 
LVL 3

Expert Comment

by:modder
ID: 6435573
Whoa... MichaelS, sorry - time out, please.

I was alerted to this question by one of the participants. Perhaps I misunderstood what they were asking for. That is possible. I'm as human as all of us.

Can the other participants please let me know what they think. Was the answer provided correct, or was it not?

If I get no responses, Michael, post another comment here in a couple of days' time, and I will reinstate the points to the original value.

Regards

modder
Community Support
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6435636
The last thing we figure out here that solution I propose will works BUT questioner seems not very advanced in such a question and if he will use this technique in some other situation probably he will have problems.

So for me it looks like my solution in that concteet situation is fine but in other situations may be not. And I finaly was agree that it's better to don't use it cos you have to clearly understand what are you doing. Any way I already spend so much time for that question that I don't care at all what will happen here.
0
 
LVL 3

Expert Comment

by:modder
ID: 6435671
Well, in that case, please accept my apologies. Here's your 100 (*A = 400) points back (that's what it was, wasn't it?)
0
 

Expert Comment

by:simon_capewell
ID: 6435742
No it isn't correct. It works in this particular case, but that doesn't mean it's correct. As soon as mettlus tries to use this technique on a member function that does use the this pointer it will not work and he'll have to ask more questions. Why not provide an solution that works in all cases?

Here's my solution (which works whether or not you use the this pointer)

// this is how the member function pointer should be defined
typedef int (cMyDLL::*PFNSUM)(int,int);


// load up the member function pointer by casting the target memory to a dword
*(DWORD*)&pfnSum=(DWORD)GetProcAddress(hinstLib, "Sum");
         
// If the function address is valid, call the function.
if (fRunTimeLinkSuccess = (pfnSum!= NULL))
{
     cMyDLL obj; // we create an instance of the class before calling a member function on it
     result=(obj.*pfnSum)(a,b);
     printf("Result via call to the DLL %d\n",result);
}
         


Note that if you declare the member function pointer typedef like this
typedef int (CALLBACK cMyDLL::*PFNSUM)(int,int);
you now get stack errors!
0
 

Expert Comment

by:simon_capewell
ID: 6435756
No it isn't correct. It works in this particular case, but that doesn't mean it's correct. As soon as mettlus tries to use this technique on a member function that does use the this pointer it will not work and he'll have to ask more questions. Why not provide an solution that works in all cases?

Here's my solution (which works whether or not you use the this pointer)

// this is how the member function pointer should be defined
typedef int (cMyDLL::*PFNSUM)(int,int);


// load up the member function pointer by casting the target memory to a dword
*(DWORD*)&pfnSum=(DWORD)GetProcAddress(hinstLib, "Sum");
         
// If the function address is valid, call the function.
if (fRunTimeLinkSuccess = (pfnSum!= NULL))
{
     cMyDLL obj; // we create an instance of the class before calling a member function on it
     result=(obj.*pfnSum)(a,b);
     printf("Result via call to the DLL %d\n",result);
}
         


Note that if you declare the member function pointer typedef like this
typedef int (CALLBACK cMyDLL::*PFNSUM)(int,int);
you now get stack errors!
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6435802
>It works in this particular case, but that doesn't mean it's correct

>As soon as mettlus tries to use this technique on a member function that does use the this pointer it will not
work.

Hey, simon_capewell, can you read what is written?

It will work in that case but will not in some other? What is the reason in your comment? Do you like to repead others or what?

Once more:

In that case it works, but will not work in other cases. Why it's not correct?

All you can say is that it's not correct cos if we will do some code modifications than..........

I think the meaning of correct is:

If it works without any problems than it's correct.

For you it seems like "If it works AND if we will do what ever we like to do with that code and it STILL works than it's correct".

In the other words, like was mentioned, before you can say that, for example, BMW or Mercedes produces not correct cars cos if you will but DIESEL instead of BENZIN it will not run???

ONCE MORE. In that particular piece of code from questioner we have a function in dll. That function has a body, concreet body. We load dll, get address of that function and call it. Why it's not correct? Cos if you will put some additional code it will not work? Than there is not correct code at all cos I can modify any piece of code and it will not work. Can you provide for me some correct code and prove that it's correct?????
0
 

Expert Comment

by:simon_capewell
ID: 6435847
Because you shouldn't be calling a non static member function without providing a this pointer. It doesn't matter whether the member function uses the this pointer or not. You must provide it. If you don't things start breaking when you make trivial changes and that isn't good practice.

You shouldn't mix calling conventions. A function with one calling convention should not be called using a different calling convention.

Sorry, but your solution just isn't correct, it only *happens* to work.
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6435882
>isn't good practice
doesn't means not correct!

>You shouldn't mix calling conventions
yes, that's what I did fixed.

>Sorry, but your solution just isn't correct, it only *happens* to work.

>Here's my solution (which works whether or not you use the this pointer)

Ahhh, I catch your point. Solution is called "correct" if "works whether or not you use the this pointer".
0
 
LVL 3

Expert Comment

by:modder
ID: 6435905
OK, guys....

This is an interesting debate, but ultimately the only person who can say whether the answer was good enough to warrant the points is mettlus, so I will ask him or her to return to this question and post a final comment about the matter. I will accept mattlus' decision as the final word.

modder
Community Support
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6436496
> In that case it works, but will not work in other cases. Why it's not correct?

Because you continue to misunderstand the underlying problem:  Your change works, but only by chance.  The actual problem is that the OP is trying to directly call a class' member function.  Plain And Simple.

You are of the impression that just because something  WORKS (or seems to), that must mean that it is CORRECT.  That is a very naive view to have esp. when you are a software developer.

You can fill your car's raditator with water, and be ABLE to drive to the end of your driveway and back without any obvious problems.  That does not mean that it is CORRECT for you to have done that.  This is a simple point being made here.

> Ahhh, I catch your point. Solution is called "correct" if "works whether or not you use the this pointer".

No, the solution is correct because it solves the *underlying* problem, not by making a change that happens to work.

(From modder):
> I will accept mattlus' decision as the final word.

Normally I would say that this is a good idea, but mettlus, as can be read above, thought that the answer was correct.  IMHO, (s)he is not capable of deciding if the answer is correct or not.

[
The reason I asked to have the point values reduced to zero as a PAQ (*ONLY FOR OTHER VIEWERS!*) is because I would like to reference this question in an article that I am writing.  I did not ask for points to be taken away from *anyone*!!!  As such, do *not* do that!

The article will discuss issues such as the one occuring here (meaning, what can happen when you try to fix something without understanding ALL of the ramifications of what you are doing.

I desire the input of others, of all experience levels, on this matter.
]

-=- James.
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6436571
>No, the solution is correct because it solves the *underlying* problem, not by making a change that
happens to work.

jtwine, I like your sample with water, but I can't agree with you. I like more my sample with BENZIN and DIESEL. If you put BENZIN in car which need BENZIN than it will work, if you put DIEZEL it will not but there is no luck or so. This is just concreat car which need BENZIN.

I can definitely be agree that it happens to work or "seems to work" if, for example, there will be some luck like address mutch, or some time mutch, or code from compiler gets generated in some special way. But this concreat sample (I mean calling member function which doesn't use "this" inside) works, and it's not a luck or what ever. It works cos it SHOULD work. Not cos it's some kind of luck.

What is luck than in terms of programming? And where the difference of "working" and "seems to be working"?

If you have a program, than it works if it works and seems to be working if there is something wrong with the code. With the solution I proposed there is NOTHING wrong.

It will never generate problems. It will work always and it's not a luck.
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6436795
> What is luck than in terms of programming?

Luck has no place in professional development.  Why?  Because luck eventually runs out!

> And where the difference of "working" and "seems to be working"?

Knowing the difference between right and wrong helps.  

> It will never generate problems. It will work always and it's not a luck.

The point of your argument is that since the user does not use the "this" pointer in the code of the class, all is well.  But the "this" pointer is there, regardless, and is INVALID.  An invalid parameter is an invalid parameter.

You are also looking at something that may also be compiler dependent here.  Changing the function to "virtual" might make a difference, for example.  And that change can occur without the OPs knowledge, because the target code IS in a DLL.  You cannot assume that you will always know the binary layout or even the implementation of something that you did not write.  As such, you should not be making assumptions about them.  Your change works, but makes the assumption that the DLL code will not ever change without the OP's knowledge.

The OP already had a correct solution (in their example code at the top), which was echoed by simon_capewell: Instantiate the class, THEN call it's members.  It is how C++ was designed to work (with non-static members).

-=- James.
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6437148
>The point of your argument is that since the user does not use the "this" pointer in the code of the
class, all is well.  But the "this" pointer is there, regardless, and is INVALID.  An invalid parameter
is an invalid parameter.

to all:

Somehow I always was thinking that we are talking about one concreat pies of code. And all of you always says that yes, it (this piece of code) works but if.......

I am talking about situation when there is NO "if". I am talking not about some standards, protocols or specifications. I am talking about code which all of you can see in the question. And with my correction it works RIGHT. There is no errors. There is no "coptile time errors", there is no "run time errors".

>Knowing the difference between right and wrong helps.  

what is right? what is wrong? is it not "works" and "doesn't works"? what is "seems to be working"?

what do you mean under "seems to be working" or "working by luck" or all that terms. If you have an EXE file, you run it and than how can you specify that it "works", "doesn't works" and "seems to be working" or "it works but only by luck"??????
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6437652
> I am talking about situation when there is NO "if".

There is only no "if" (in this case) if the function is either a "normal" function, or a non-static member function.

> If you have an EXE file, you run it and than how can you specify that it "works", "doesn't works" and "seems to be
> working" or "it works but only by luck"?

I can easily create an app that will run successfully at run-time, but leaks small amounts of memory.  Will it "work"?  Sure.  Will it "run"?  Sure.  Will it crash?  Not Likely.  Is it *correct*?  *NO*!

As an example, I have seen *released* multi-threaded applications that have internal race conditions, but never really caused problems because they were always run on uni-processor systems.  Running the app on an multi-CPU system makes the race conditions more likely to occur.  The reason is simple: The race conditions, which are bad (even if they never *caused* problems before), caused the problem.  

I have seen poorly coded MT applications start to crash or otherwise misbehave because an unrelated code change changed the timing of something.  Those applications ran by luck, nothing more.

Poor code was the underlying problem in both examples (and hence, the REAL problem), not a "different situation".  

The "different situation" exacerbated an *existing* problem, nothing more.

I do not understand what that is such a hard concept to understand: I, too, once thought that "works" was good enough ("It compiles?  It runs?  Ship It!!!").  But I have learned that "It Works" does not always mean "It's Correct".

This can go on for ever...  But I assure you: one day, something will "click", and you will look back on this and wonder "what the HELL was I thinking?"  

Been there.  Done that.  Believe me.

-=- James.
0
 
LVL 3

Expert Comment

by:modder
ID: 6437922
Hello again,

I wish I knew more about C++

But I am a programmer, and have been for 12 years. I can see the value of a discussion even if I don't fully understand the subject matter. And I recognise that this is a very fruitful discussion. Also, I'd like to thank you all for keeping this discussion on such a professional level. You all disagree with each other in the most gentle(wo)manly fashion, and I think I will keep a link to this thread so I can point out how it *should* be done in those threads where a disagreement does escalate into a flaming match.

With regards to my decision. You are discussing this from a technical point of view, and from that point of view I can understand very well where you are coming from. But my decision is a procedural one, not one based on technical merit. As an administrator of the site I have to work this way.

I can only justify contravening an asker's decision to award points in the following circumstances:

1) Asker is a blatant abuser of the site
2) Asker accidentally accepted the wrong answer

Neither of those is the case here. Whatever your technical reasons are for disagreeing with the proposed solution, ultimately mettlus decided that the solution put forward by MichaelS worked *for this particular case*, and because of that mettlus decided to accept the answer. And I have to respect that decision. Initially I thought that this might be a case of 2), but I realised my mistake and reversed it.

Finally, about this question being a 10-point PAQ. I honestly do not think that anyone who spends 10 points on this question should consider those 10 points wasted. On the contrary. A question is posted, a solution is given, and then the merits of that solution and alternative solutions are discussed at great length. This thread contains a wealth of information. It's well worth spending 10 points on.

So, once again, thank you.

modder
Community Support

0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6438154
> I can only justify contravening an asker's decision to award points in the following circumstances: [...]

I still do not know who asked to change points awarded, or why.  If this is referring to my letter, someone was confused.

> Finally, about this question being a 10-point PAQ. I honestly do not think that anyone who spends 10 [...]
> This thread contains a wealth of information. It's well worth spending 10 points on.

Again, my original message was not read or understood correctly.  The article that I mention above (and in the original email) is going to be presented to an audience whom many of which are not registered at this site.

Having to go through registration just to view this would render the article incomplete.  I am, of course, under the impression that yoiu should not need to be registered in order to view a *free* PAQ.  That makes sense to me.  But as shown here, what makes sense to me clouds others.  Regardless, I will see what happends and just figure a way to deal with it.

-=- James.
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 6439503
well, for me that discusson is going not for the points and looks like not with the questioner :))))

James, I also think that it can go for years and we can discuss it longer and longer. I propose to stop it and hope that we will be able to "fight" again (I mean you and me and other experts will still participate on thet site and EE will still works and ....) on some other question/problem :)
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6440544
Agreed.  See you one the battlefield some day! :)

-=- James.
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now