vendredi 6 mars 2020

Smart pointer with custom deleter as class member

My situation is as follows: I have a .dll file and a .h header with a purely virtual class MainWindow declaration. There are two type definitions in the header file:

typedef MainWindow* (*CREATE_INTERFACE)();
typedef void (*DELETE_INTERFACE)(MainWindow* Window);

which allow me to create and delete an object of the same type as a virtual class.

I would like that loading support for this dynamic library to be defined in my class, let's call it class Loader. I would like one of my class members to be a smart pointer defined as follows:

std::unique_ptr <MainWindow,DELETE_INTERFACE> UI_Driver;

The simplified code below (without error handling):

class Loader
{
    private:
    HINSTANCE DllHandle;
    CREATE_INTERFACE FactoryFunction;
    DELETE_INTERFACE CustomDeleterFunction;
    std::unique_ptr<MainWindow,DELETE_INTERFACE> UI_Driver;

    std::unique_ptr<MainWindow,DELETE_INTERFACE> LoadExternalLibrary()
    {
        std::wstring WideFileName=L"MainWindow.dll";
        std::string FileName(std::begin(WideFileName),std::end(WideFileName));
        this->DllHandle=::LoadLibrary(WideFileName.c_str());
        // Get the function from the DLL
        FactoryFunction=reinterpret_cast<CREATE_INTERFACE>(::GetProcAddress(DllHandle,"Create"));
        CustomDeleterFunction=(DELETE_INTERFACE)GetProcAddress(DllHandle,"Delete");
        return std::unique_ptr<MainWindow,DELETE_INTERFACE>(FactoryFunction(),CustomDeleterFunction);
     };

     UI_Service() : UI_Driver(LoadExternalLibrary())
     {

     }

     ~UI_Service()
     {
         if(UI_Driver)
             ::FreeLibrary(this->DllHandle);
     }

     void ShowWindow()
     {
        UI_Driver->Show();
     }
};

The code compiles correctly, loading functions from the .dll library is also succesfull. A MainWindow defined in header has a Show() method that draws the user interface. If I try to call it like above with the ShowWindow() method from my class Loader, the window does not appear.

int main()
{
 Loader MyLoader;
 MyLoader.ShowWindow(); // <- window does not appear, program crashes
}

BUT it appears if I call this method immediately after creating the pointer in the LoadExternalLibrary() method as below:

so instead:

return std::unique_ptr<Eol_MainWindow_Driver_Generic,DELETE_INTERFACE>(FactoryFunction(),CustomDeleterFunction);

i can write:

std::unique_ptr<Eol_MainWindow_Driver_Generic,DELETE_INTERFACE> UI(FactoryFunction(),CustomDeleterFunction);
UI->Show(); // <- Window appears
return UI; // <- It will never happen because the Show() is blocking the thread

What is going on? Why does the created unique_ptr with custom deleter stop working after copying?

Aucun commentaire:

Enregistrer un commentaire