Dear Kind-Coders,

I am trying to learn to use boost::shared_ptr to manage the lifetime of a DLL, but I am having a type conversion problem whilst setting it up.
Please see the following code:

#include <boost/make_shared.hpp>
int main()
{
    {
        class CMyClass {
        public:
            CMyClass() {}
            ~CMyClass() {}

            int MyInt;
        };

        typedef void* (*fpFunct1)();

        fpFunct1 CreateFoo;

        /*********************************************** 
             Build error because cannot convert 
             from 'HINSTANCE__ *' to 'HINSTANCE__ **'
        ************************************************/        
        boost::shared_ptr<HMODULE> spHDL (LoadLibrary("DllMain.dll"), FreeLibrary);

        // get the function pointer
        CreateFoo = (fpFunct1)(GetProcAddress(*spHDL, "CreateFooClassInstance"));

        // get pointer to object
        auto pMyClass = boost::make_shared<CMyClass*>
            (static_cast<CMyClass*> (CreateFoo()));          

        (*pMyClass)->MyInt = 9;


    } // See destructor/custom_deleter here (FreeLibrary())

    return 0;
}

As it is I get the error:
...boost_1_55_0\boost\smart_ptr\shared_ptr.hpp(364): error C2440: 'initializing' : cannot convert from 'HINSTANCE__ *' to 'HINSTANCE__ **'

If I do boost::shared_ptr<HINSTANCE__> spHDL (LoadLibrary("DllMain.dll"), FreeLibrary); instead I get the error:
...error C2664: 'GetProcAddress' : cannot convert parameter 1 from 'HINSTANCE__' to 'HMODULE'

Please can you show me how this is supposed to be done correctly.
Thanks in advance...
Elixir42

Technically, you could make this work using this:

boost::shared_ptr<HINSTANCE__> spHDL (LoadLibrary("DllMain.dll"), FreeLibrary);

// get the function pointer
CreateFoo = (fpFunct1)(GetProcAddress(spHDL.get(), "CreateFooClassInstance"));

However, this reliance on HINSTANCE__ makes me cringe. The problem is that you are not really supposed to assume that HMODULE is defined as HINSTANCE__*. The Win32 API does not specify what HMODULE is defined as, and you should not rely on what it is. Anything that isn't specified is something you should not rely on. For example, HMODULE could be an integer type, and not a pointer.

I don't think that using a shared_ptr is really appropriate here. I think you should simply create a RAII wrapper around the loaded module, like this:

class DLLLoader {
  private:
    HMODULE h_inst;
  public:

    DLLLoader(const char* libName) : h_inst(LoadLibrary(libName)) { };
    ~DLLLoader() {
      if( h_inst )
        FreeLibrary(h_inst);
    };

    DLLLoader(const DLLLoader&) = delete;
    DLLLoader& operator=(const DLLLoader&) = delete;

    DLLLoader(DLLLoader&& rhs) : h_inst(rhs.h_inst) {
      rhs.h_inst = HMODULE(0);
    };
    DLLLoader& operator=(DLLLoader&& rhs) {
      h_inst = rhs.h_inst;
      rhs.h_inst = HMODULE(0);
      return *this;
    };

    template <typename FuncPtrType>
    FuncPtrType GetProcAddress(const char* procName) const {
      return (FuncPtrType)(GetProcAddress(h_inst, procName));
    };
};

And then, you can create a DLLLoader object either by itself or wrapped in any smart-pointer you like. Like, for example:

boost::shared_ptr<DLLLoader> spDLL(new DLLLoader("DllMain.dll"));

// get the function pointer
CreateFoo = spDLL->GetProcAddress("CreateFooClassInstance");

That's great, thank you, but there is a bug in:

CreateFoo = spDLL->GetProcAddress("CreateFooClassInstance");

as it gives me the error: error C2783: 'FuncPtrType CDLLLoader::GetProcAddress(const char *) const' : could not deduce template argument for 'FuncPtrType'

I tried other permutations including .template keyword and even stipulating the template argument type like:

CreateFoo = spDLL->GetProcAddress<fpFunct1>("CreateFooClassInstance");

but this gives me this error:
error C2780: 'FuncPtrType CDLLLoader::GetProcAddress(const char *) const' : expects 1 arguments - 2 provided
Thank you, humbley, for your time.

Additional:
I can make it work if I call GetProcAddress manually and pass in a public made handle from the class. But this is not very encapsulated though.
Please can you advise me, as to the remedy of the error, as I'd like to use the templated member function

CDLLLoader::GetProcAddress

instead...!

Oh, sorry about those errors, I wrote the thing a bit too quickly. The first error you got about "could not deduce template argument for 'FuncPtrType'" is solved exactly as you did.

The second error, about "expects 1 arguments - 2 provided", has to do with a name conflict. The problem is that the GetProcAddress function could refer to either the member function of CDLLLoader or the Win32 API function of the same name. So, just change the name of that function in the CDLLLoader class:

class DLLLoader {
  private:
    HMODULE h_inst;
  public:

    //...

    template <typename FuncPtrType>
    FuncPtrType GetFunctionPtr(const char* procName) const {
      return (FuncPtrType)(GetProcAddress(h_inst, procName));
    };
};

And then call it with:

CreateFoo = spDLL->GetFunctionPtr<fpFunct1>("CreateFooClassInstance");

That should work (sorry, I can't test it, I'm not under Windows at the moment).

Yes that's it!
I can't believe I didn't think of that!
God bless you and thanks...!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.