locked
call a dll function RRS feed

  • Question

  • hi i have been trying to learn how to create dll's

    but im having some big problems with my code i cannot call a class function
    inside a dll.

    i have some code below that best explains my problems

    it loads the dll but fails when it loads the function why

    // class that loads dll
    int main(){
    
    //typedef INT_PTR (*FARPROC)(void);
    
       HMODULE sdl_library = LoadLibrary("TESTTHEDLL.dll");
    	if( sdl_library == NULL) {
    	  
    		cout << "Load dll failed" << endl;
    		system("PAUSE");
    
    	} 
    
    	else 
    	{
    	   // use the result in a call to GetProcAddress
    	}
    
    	FARPROC initializer = GetProcAddress(sdl_library,"Hello");
    	if(initializer == NULL) {
    	   
    		cout << "Load function failed" << endl;
    		system("PAUSE");
    
    	} 
    
    	else 
    	{
    	   // cast initializer to its proper type and use
    	}
    	return 0;
    }


    // dll

    most of this was generated by visual studio. exept for my fuction hello
    // header
    #ifdef TESTTHEDLL_EXPORTS
    #define TESTTHEDLL_API __declspec(dllexport)
    #else
    #define TESTTHEDLL_API __declspec(dllimport)
    #endif
    
    // This class is exported from the TESTTHEDLL.dll
    class TESTTHEDLL_API CTESTTHEDLL {
    public:
    	CTESTTHEDLL(void);
    	// TODO: add your methods here.
    	void Hello();
    };
    
    extern TESTTHEDLL_API int nTESTTHEDLL;
    
    TESTTHEDLL_API int fnTESTTHEDLL(void);


    //cpp
    // This is an example of an exported variable
    TESTTHEDLL_API int nTESTTHEDLL=0;
    
    // This is an example of an exported function.
    TESTTHEDLL_API int fnTESTTHEDLL(void)
    {
    	return 42;
    }
    
    // This is the constructor of a class that has been exported.
    // see TESTTHEDLL.h for the class definition
    CTESTTHEDLL::CTESTTHEDLL()
    {
    	return;
    }
    
    void CTESTTHEDLL::Hello()
    {
    	cout << "Worked" << endl;
    	system("PAUSE");
    
    }

    i know that im missing the pointer to the load function. but thats
    not the point it fails when i try to run it and the output is : Load function failed
    Monday, January 4, 2010 9:24 AM

Answers

  • but what is the point of the #include myclass.h inside the main class?

    isnt it supposed to be dynamic loading dll's that you don't know the name of there header files

    if someone answers that i would much appriciate it thanks

    Typically one deploys a header file along with the DLL for use with C/C++ programs. Even Microsoft does it. For example, if you want to call the into the kernel32.dll to execute FindFirstFile(), you are going to need to know the layout of WIN32_FIND_DATA. You can't determine this through GetProcAddress(); you need a header file, and of course Microsoft provides it: windows.h.

    COM DLL's and .NET assemblies are designed differently. For COM DLL's one can embed a type library so that this information can be determined on the fly. For .NET assemblies, one can use reflection. But that's not what we are talking about here.



    • Marked as answer by Wesley Yao Wednesday, January 13, 2010 3:15 AM
    Tuesday, January 5, 2010 1:23 AM
  • When you build your DLL you should get an import library (.lib) of the same name. Link this library to your executable.

    An alternative, which I prefer, is to derive your class from a pure interface

    // MyInterface.h
    class MyInterface
    {
    public:
      virtual int getX() const = 0;
      virtual void Hello() = 0;
    };


    // code.cpp
    class MyClass: public MyInterface
    {
    public:
        MyClass()
        : mX(60) {}
        virtual int getX() const { return mX; }
        virtual void Hello() {} // my new function hello
    private:
        int mX;   
    };

    extern "C"  void __declspec(dllexport) createMyClass(MyInterface** instance)
    {
       *instance = new MyClass();
    }

    Your .exe includes only MyInterface.h and knows nothing about the concrete class MyClass. Note that you can use GetProcAddress() to access the createMyClass() export.

    You should export another function that destroys the instance:

    extern "C"  void __declspec(dllexport) destroyMyClass(MyInterface* pInstance)
    {
       delete (MyClass*)pInstance
    }

    in case your exe and dll are using different heaps.

     

    David Wilkinson | Visual C++ MVP
    • Marked as answer by Wesley Yao Wednesday, January 13, 2010 3:15 AM
    Tuesday, January 5, 2010 3:45 AM

All replies

  • You cannot use GetProcAddress() to get pointer to member function. To call Hello(), you need an object of type CTESTTHEDLL. Use implicit linking using a lib file instead of LoadLibrary().
    Monday, January 4, 2010 10:11 AM
  • it needs to be explicit linking to a external dll. so how can i achieve this?
    Monday, January 4, 2010 10:32 AM
  • Look at this sample.
    Monday, January 4, 2010 11:10 AM
  • but what is the point of the #include myclass.h inside the main class?

    isnt it supposed to be dynamic loading dll's that you don't know the name of there header files

    if someone answers that i would much appriciate it thanks


    this code was a reference to your link above

    #include <Windows.h>
    #include <iostream>
    #include "myclass.h"
    
    int main()
    {
    	HINSTANCE dynamicLibrary = ::LoadLibrary(L"myclass.dll");
    
    	typedef void (*createMyClassFuncPtr)(MyClass**);
    	createMyClassFuncPtr createInstanceFunction;
    	createInstanceFunction = (createMyClassFuncPtr)::GetProcAddress(dynamicLibrary, "createMyClass");
    
    	MyClass* myClass = NULL;
    	createInstanceFunction(&myClass);
    
    	std::cout << myClass->getX() << std::endl;
    
    	FreeLibrary(dynamicLibrary);
    
    	return 0;
    }

    Tuesday, January 5, 2010 1:00 AM
  • but what is the point of the #include myclass.h inside the main class?

    isnt it supposed to be dynamic loading dll's that you don't know the name of there header files

    if someone answers that i would much appriciate it thanks

    Typically one deploys a header file along with the DLL for use with C/C++ programs. Even Microsoft does it. For example, if you want to call the into the kernel32.dll to execute FindFirstFile(), you are going to need to know the layout of WIN32_FIND_DATA. You can't determine this through GetProcAddress(); you need a header file, and of course Microsoft provides it: windows.h.

    COM DLL's and .NET assemblies are designed differently. For COM DLL's one can embed a type library so that this information can be determined on the fly. For .NET assemblies, one can use reflection. But that's not what we are talking about here.



    • Marked as answer by Wesley Yao Wednesday, January 13, 2010 3:15 AM
    Tuesday, January 5, 2010 1:23 AM
  • one last question i made a new function Hello()
    how do i instance it in the cpp file


    // header of dll
    #ifndef __MYCLASS_H__
    #define __MYCLASS_H__
    
    #include <iostream>
    
    using namespace std;
    
    class __declspec(dllexport) MyClass
    {
    public:
    	inline MyClass()
    		: mX(60) {}
    
    	inline int getX() const { return mX; }
    
    	void Hello(); // my new function hello
    
    private:
    	int mX;
    
    	
    };
    
    extern "C" { void __declspec(dllexport) createMyClass(MyClass** instance); }
    
    #endif


    // cpp of dll

    #include "myclass.h"
    
    extern "C"
    {
    	void createMyClass(MyClass** instance)
    	{
    		*instance = new MyClass();
    	}
    }
    
    void MyClass::Hello(){          } // this wont work so where do i put the functions?!!!!

    i get a linking error whenever i try to call it
    Tuesday, January 5, 2010 2:09 AM
  • When you build your DLL you should get an import library (.lib) of the same name. Link this library to your executable.

    An alternative, which I prefer, is to derive your class from a pure interface

    // MyInterface.h
    class MyInterface
    {
    public:
      virtual int getX() const = 0;
      virtual void Hello() = 0;
    };


    // code.cpp
    class MyClass: public MyInterface
    {
    public:
        MyClass()
        : mX(60) {}
        virtual int getX() const { return mX; }
        virtual void Hello() {} // my new function hello
    private:
        int mX;   
    };

    extern "C"  void __declspec(dllexport) createMyClass(MyInterface** instance)
    {
       *instance = new MyClass();
    }

    Your .exe includes only MyInterface.h and knows nothing about the concrete class MyClass. Note that you can use GetProcAddress() to access the createMyClass() export.

    You should export another function that destroys the instance:

    extern "C"  void __declspec(dllexport) destroyMyClass(MyInterface* pInstance)
    {
       delete (MyClass*)pInstance
    }

    in case your exe and dll are using different heaps.

     

    David Wilkinson | Visual C++ MVP
    • Marked as answer by Wesley Yao Wednesday, January 13, 2010 3:15 AM
    Tuesday, January 5, 2010 3:45 AM