RAD Studio
ContentsIndex
PreviousUpNext
Implementing the Wizard Interfaces

Every wizard class must implement at least IOTAWizard, which requires implementing its ancestors, too: IOTANotifier and IInterface. Form and project wizards must implement all their ancestor interfaces, namely, IOTARepositoryWizard, IOTAWizard, IOTANotifier, and IInterface

For C++, to use NotifierObject as a base class you must use multiple inheritance. Your wizard class must inherit from NotifierObject and from the wizard interfaces that you need to implement, such as IOTAWizard. Because IOTAWizard inherits from IOTANotifier and IInterface, there is an ambiguity in the derived class: functions such as AddRef() are declared in every branch of the ancestral inheritance graph. To resolve this problem, pick one base class as the primary base class and delegate all ambiguous functions to that one class. For example, the class declaration might look as follows:

class PACKAGE MyWizard : public NotifierObject, public IOTAMenuWizard {
    typedef NotifierObject inherited;
    public:
        // IOTAWizard
        virtual AnsiString __fastcall GetIDString();
        virtual AnsiString __fastcall GetName();
        virtual TWizardState __fastcall GetState();
        virtual void __fastcall Execute();
        // IOTAMenuWizard
        virtual AnsiString __fastcall GetMenuText();
      void __fastcall AfterSave();
        void __fastcall BeforeSave();
        void __fastcall Destroyed();
        void __fastcall Modified();
    protected:
        // IInterface
        virtual HRESULT __stdcall QueryInterface(const GUID&, void**);
        virtual ULONG __stdcall AddRef();
        virtual ULONG __stdcall Release();
};

 

// implementation
ULONG __stdcall MyWizard::AddRef()  { return inherited::AddRef(); }
ULONG __stdcall MyWizard::Release() { return inherited::Release(); }
HRESULT __stdcall MyWizard::QueryInterface(const GUID& iid, void** obj)
{
    if (iid == __uuidof(IOTAMenuWizard)) {
        *obj = static_cast<IOTAMenuWizard*>(this);
        static_cast<IOTAMenuWizard*>(*obj)->AddRef();
        return S_OK;
    }
    if (iid == __uuidof(IOTAWizard)) {
        *obj = static_cast<IOTAWizard*>(this);
        static_cast<IOTAWizard*>(*obj)->AddRef();
        return S_OK;
    }
    return inherited::QueryInterface(iid, obj);
}

Your implementation of IInterface must follow the normal rules for Delphi interfaces, which are the same as the rules for COM interfaces. That is, QueryInterface performs type casts, and _AddRef and _Release manage reference counting. You might want to use a common base class to simplify writing wizard and notifier classes. For this purpose, the ToolsAPI unit defines a class, TNotifierObject, which implements IOTANotifier interface with empty method bodies. 

You can write a class similar to TNotifierObject in C++.

class PACKAGE NotifierObject : public IOTANotifier {
    public:
        __fastcall NotifierObject() : ref_count(0) {}
        virtual __fastcall ~NotifierObject();
        void __fastcall AfterSave();
        void __fastcall BeforeSave();
        void __fastcall Destroyed();
        void __fastcall Modified();
    protected:
        // IInterface
        virtual HRESULT __stdcall QueryInterface(const GUID&, void**);
        virtual ULONG __stdcall AddRef();
        virtual ULONG __stdcall Release();
    private:
        long ref_count;
};

 

// implementation
ULONG __stdcall NotifierObject::AddRef()
{
    return InterlockedIncrement(&ref_count);
}
ULONG __stdcall NotifierObject::Release()
{
    ULONG result = InterlockedDecrement(&ref_count);
    if (ref_count == 0)
        delete this;
    return result;
}
HRESULT __stdcall NotifierObject::QueryInterface(const GUID& iid, void** obj)
{
    if (iid == __uuidof(IInterface)) {
        *obj = static_cast<IInterface*>(this);
        static_cast<IInterface*>(*obj)->AddRef();
        return S_OK;
    }
    if (iid == __uuidof(IOTANotifier)) {
        *obj = static_cast<IOTANotifier*>(this);
        static_cast<IOTANotifier*>(*obj)->AddRef();
        return S_OK;
    }
    return E_NOINTERFACE;
}

Although wizards inherit from IOTANotifier, and must therefore implement all of its functions, the IDE does not usually make use of those functions, so your implementations can be empty (as they are in TNotifierObject). Thus, when you write your wizard class, you need only declare and implement those interface methods introduced by the wizard interfaces, accepting the TNotifierObject implementation of IOTANotifier.

// C++ empty implementations
void __fastcall NotifierObject::AfterSave()  {}
void __fastcall NotifierObject::BeforeSave() {}
void __fastcall NotifierObject::Destroyed()  {}
void __fastcall NotifierObject::Modified()   {}
Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
What do you think about this topic? Send feedback!