tags:

views:

37

answers:

3
#include "Calc.h"
#include<iostream>
#include <windows.h>
#include <WINERROR.H.>

typedef void (WINAPI * PCTOR) ();
int main()
{
    HMODULE hMod = LoadLibrary (L"Calci.dll");
    if (NULL == hMod)
    {
        printf ("LoadLibrary failed\n");
        return 1;
    }
    CCalc *pCCalc = (CCalc *) malloc (sizeof (CCalc));
    if (NULL == pCCalc)
    {
        printf ("memory allocation failed\n");
        return 1;
    }
    PCTOR pCtor = (PCTOR) GetProcAddress (hMod, "CCalc");//127 error
    int err = GetLastError();
    if (NULL == pCtor)
    {
        printf ("GetProcAddress failed\n");
        return 1;
    }
    __asm { MOV ECX, pCCalc };
    pCtor ();
    return 0;
}

//dll file
#include <tchar.h>


#ifdef CALC_EXPORTS
#define CALC_API __declspec (dllexport)
#else
#define CALC_API __declspec (dllimport)
#endif

#define SOME_INSTN_BUF        260

class CALC_API CCalc
{
private:
char m_szLastUsedFunc[SOME_INSTN_BUF];

public:
    CCalc (); 

    int Add (int i, int j);
    int Sub (int i, int j);
    TCHAR* GetLastUsedFunc ();

};
A: 

Use dumpbin.exe to check the exact name of the export in the DLL. Maybe it doesn't exist at all?

If you have a chance to use import library instead of LoadLibrary API, it is better.

Pavel Radzivilovsky
excuting dumpbin.exe showing that msdb80.dll not found.:(
What? You mean dumpbin doesn't work at all, even doesn't show help message? If so, use Visual Studio Command Prompt to run dumpbin.
Pavel Radzivilovsky
A: 

You're invoking GetProcAddress (hMod, "CCalc"), however "CCalc" isn't the name of a function: it's the name of a class.

You're trying to load the address of the CCalc::CCalc default constructor: to do that, use a tool (e.g. dumpbin) to discover the "decorated" name of the constructor.

However instead of trying to dynamic-load and invoke the constructor, a more usual way to implement this functionality would be to create a static factory method in the DLL, e.g. like this:

class CALC_API CCalc 
{ 
public:
    static CCalc* create() { return new CCalc(); }

private:
    //doesn't need to be public because users instantiate this class using 
    //the static create method
    CCalc();  

public:
    virtual int Add (int i, int j); 
    virtual int Sub (int i, int j); 
    virtual TCHAR* GetLastUsedFunc ();

    virtual ~CCalc() {}
};

Then use GetProcAddress to get the address of the static CCalc::create function, which because it's static you can invoke without using assembly to mess with ECX.

ChrisW
excuting dumpbin.exe showing that msdb80.dll not found.:(
You can also get decorated names from the `*.map` file which is optionally enabled via a linker option, or from one of the compiler listing/assembly files which you can optiionally enable via a compiler option.Or if you have a `create` function at global scope (i.e. not declared as a member of a class), then you can use `extern "c"` to disable its name mangling (so that you can predict/know its name just from looking at the source). Or another tool to look at the binary, apart from `dumpbin.exe`, is the Dependecy Walker `depends.exe`.
ChrisW
A: 

You can't use GetProcAddress for classes. This does not work. Only functions you can resolve their names are unmangled "C" functions.

For example:

extern "C" __declspec(dllexport) CCalc *create_calc()
{
     return new CCalc;
}

Now, you can resolve it using.

GetProcAddress(halnder,"create_calc");

As create_calc is not-mangled function.

Also you will have to provide abstract API class without implementation and make CCalc inherit ACalc, otherwise you'll get unresolved symbols tying to compile your application. Because actual add and remove member functions are not known to the application.

class ACalc {
public:
      virtual add(int i,int j) = 0;
      ...
      virtaul ~ACalc() {}
};

class CCalc : public ACalc {
public:
      virtual add(int i,int j) { ... };
      ...
};

And in the main program

ACalc *ptr= call_for_dll_function
Artyom
it showing error 'CCalc' : cannot instantiate abstract class
@Artyom - I don't think it needs to be pure/abstract; instead, just defining `add` as virtual (even concrete virtual) is sufficient for the caller to use the vtable.
ChrisW
still confussed. showing error"public: int __thiscall CCalc::Add(int,int)" (?Add@CCalc@@QAEHHH@Z) referenced in function _maini have made the change as mention by ChrisW
@user323422 you should not use CCalc class **at all** in your main program but abstract one only.
Artyom