ウィザード インターフェイスの実装

提供: RAD Studio
移動先: 案内検索

ウィザード クラスの作成 への移動

すべてのウィザード クラスでは、少なくとも IOTAWizard を実装する必要があります(その上位クラス、IOTANotifier と IInterface の実装も必要)。 フォーム ウィザードとプロジェクト ウィザードでは、そのすべての上位インターフェイス、つまり IOTARepositoryWizard、IOTAWizard、IOTANotifier、および IInterface を実装する必要があります。

C++ の場合、NotifierObject を基底クラスとして使用するには、複数の継承を使用する必要があります。 ウィザード クラスは、NotifierObject から、および実装を要するウィザード インターフェイス(IOTAWizard など)から継承する必要があります。 IOTAWizard は IOTANotifier と IInterface から継承するので、派生クラスにはあいまいな要素があります。たとえば、AddRef() 関数は継承の上位からみてすべての下位クラスで宣言されます。 この問題を解決するためには、最上位の基底クラスとして 1 つの基底クラスを選択し、このクラスにすべてのあいまいな関数を割り当てます(デリゲート)。 たとえば、クラスの宣言は次のようになります。

   class PACKAGE MyWizard : public NotifierObject, public IOTAMenuWizard {
  	typedef NotifierObject inherited;
  	public:
  		// IOTAWizard
  		virtual UnicodeString __fastcall GetIDString();
  		virtual UnicodeString __fastcall GetName();
  		virtual TWizardState __fastcall GetState();
  		virtual void __fastcall Execute();
  		// IOTAMenuWizard
  		virtual UnicodeString __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();
  };
 
  // 実装
  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);
  }


Delphi では、メニュー ウィザードを作成するために追加で IOTAWizard と IOTAMenuWizard の 2 つのインターフェイスを実装する必要があります。 次に示す例は、メニュー ウィザード用のスケルトン コードです。

 
  interface
  uses
    ToolsAPI,...; 
  Type
  MyWizard = class(TNotifierObject, IOTAWizard, IOTAMenuWizard)
    public
      { IOTAWizard }
      function GetIDString: string;
      function GetName: string;
      function GetState: TWizardState;
      procedure Execute;
  
      { IOTAMenuWizard }
      function GetMenuText: string;
    end;
  procedure Register;
 
  implementation
  const
    SADPMenuIdString ='ADP.Headline';
    SADPMenu ='About...';
  .....
  procedure MyWizard.Execute;
  begin
    if ADPHeadlinesForm = nil then ADPHeadlinesForm := TADPHeadlinesForm.Create(Application) ;
    ADPHeadlinesForm.Show;
    ADPHeadlinesForm.BringToFront;
  end;
  function MyWizard.GetIDString: string;
  begin
    Result := SADPMenuIdString;
  end;
  function MyWizard.GetMenuText: string;
  begin
    Result := SADPMenu;
  end;
  function MyWizard.GetName: string;
  begin
    Result := SADPMenuIdString;
  end;
  function MyWizard.GetState: TWizardState;
  begin
    Result := [wsEnabled];
  end;
  end.


IInterface の実装は、Delphi インターフェイスの標準規則に従う必要があります。これは、COM インターフェイスの規則と同じです。 つまり、QueryInterface で型キャストを行い、_AddRef_Release で、参照カウントを管理します。共通の基底クラスを使用すると、ウィザード クラスとノーティファイア クラスの記述を単純化できます。 このために、ToolsAPI ユニットは TNotifierObject クラスを定義します。これは、IOTANotifier インターフェイス(メソッド本体はなし)を実装したものです。

C++ で TNotifierObject と同様のクラスを記述できます。

  
 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;
  };
 
  // 実装
  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;
  }


Delphi で、TNotifierObject は次のように定義されます。

 
  type
  TNotifierObject = class(TInterfacedObject, IOTANotifier)
  protected
     // IUnknown の実装
     function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
     function _AddRef: Integer; stdcall;
     function _Release: Integer; stdcall;
     // IOTANotifier の実装
     procedure AfterSave;
     procedure BeforeSave;
     procedure Modified;
     procedure Destroyed;
  end;
 
  implementation
  function TNotifierObject.QueryInterface(const IID: TGUID; out Obj):HResult;
  const
   E_NOINTERFACE = HResult($80004002);
  begin
   if GetInterface(IID, Obj) then
     Result := 0
   else
     Result := E_NOINTERFACE;
  end;
  function TNotifierObject._AddRef: Integer;
  begin
   // 参照カウントは実装されていない
   Result := -1;
  end;
  function TNotifierObject._Release: Integer;
  begin
   // 参照カウントは実装されていない
   Result := -1;
  end;


ウィザードは IOTANotifier から継承するので、そのすべての関数を実装する必要がありますが、IDE は通常これらの関数を利用しないので、実装は空でもかまいません(TNotifierObject と同様)。 このため、独自のウィザード クラスを記述するときは、IOTANotifier の TNotifierObject の実装を受け入れて、ウィザード インターフェイスによって導入されたこれらのインターフェイス メソッドを宣言して実装するだけです。

 
  // C++ の空実装
  void __fastcall NotifierObject::AfterSave()  {}
  void __fastcall NotifierObject::BeforeSave() {}
  void __fastcall NotifierObject::Destroyed()  {}
  void __fastcall NotifierObject::Modified()   {}
 
  //Delphi の空実装
     procedure TXPEditReaderStream.AfterSave;
   begin
     // 何もしない
   end;
    procedure TXPEditReaderStream.BeforeSave;
  begin
   // 何もしない
  end;
    procedure TXPEditReaderStream.Modified;
  begin
   // 何もしない
  end;


関連項目