テクニカル ノート 41: MFC/OLE1 から MFC/OLE 2 への移植
[!メモ]
次のテクニカル ノートは、最初にオンライン ドキュメントの一部とされてから更新されていません。結果として、一部のプロシージャおよびトピックが最新でないか、不正になります。最新の情報について、オンライン ドキュメントのキーワードで関係のあるトピックを検索することをお勧めします。
移行に関する問題の概要
OLE のデザインの目標の 1 つが、 MFC 2.5 の 2 種類のクラス (および高い OLE 1.0 のサポートの MFC 2.0 で設定された同じアーキテクチャの多くを保持することでした。その結果、 MFC 2.0 の同じ OLE クラスの多くは、 MFC (COleDocument、 COleServerDoc、 COleClientItem、 COleServerItem)のこのバージョンにあります。また、これらのクラスの API の多くはまったく同じです。ただし、 OLE 2 は、 OLE 1.0 と調査に異なるため、詳細の一部が変更されたと想定できます。MFC 2.0 が付いて OLE1 サポートに慣れている場合は、 MFC 2.0 のサポートと家庭に感じます。
既存の MFC/OLE1 アプリケーションをより、 OLE 2 の機能を追加すると、このメモを最初に読み込む必要があります。ここでは、 MFC 2.0 に含まれる 2 アプリケーションを移植するとき OLE1 機能を MFC/OLE 2 に移植する間、見つかった問題への対処を説明する、発生する可能性のある一般的な問題を網羅し、: MFC OLE、 OCLIENT と HIERSVRをサンプリングします。
MFC のドキュメント/ビュー アーキテクチャは重要です。
アプリケーションが MFC のドキュメント/ビュー アーキテクチャを使用せず、アプリケーションに OLE 2 のサポートを追加するには、ドキュメント/ビューに移動する時間が長くなります。MFC OLE の利点の多くは、 2 種類のクラス アプリケーションが MFC の組み込みアーキテクチャおよびコンポーネントを使用する場合のみ実現されます。
MFC アーキテクチャを使用しないサーバーまたはコンテナーの実行は可能、ただし推奨されていません。
独自の代わりに、 MFC 実装を使用します。
MFC に実装された、 「」 CToolBarは、 CStatusBarのような分類し、 CScrollView に OLE 2 のサポートのための組み込みの特殊なケース コードがあります。したがって、アプリケーションでこれらのクラスを使用できる場合、 OLE を認識するために入力した工数を利用できます。もう一度、これらのオブジェクトに独自のロール 「」クラスには、ここにできますが、推奨されません。同様の機能を実行する必要がある場合は、 MFC ソース・コードは、 OLE の細かい条項の一部を処理するための優れた参照 (特に埋め込み先編集の有効化については)。
MFC のサンプルのコードをチェックします。
OLE 機能をいくつかの MFC サンプルがあります。これらのアプリケーションには、それぞれ異なる角度からの OLE を実行します:
HIERSVR がサーバー アプリケーションとして主に意味します。OLE 2. で使用できる多くの OLE 機能を実行することが MFC/OLE1 アプリケーションとして MFC 2.0 に含まれています MFC/OLE 2 に移植され、次に、こうしたが拡張され。
OCLIENT は、このコンテナーの観点からの OLE 機能の多くを示すものであるスタンドアロン コンテナー アプリケーションです。このサンプルは、 MFC 2.0 からすぎる移植して埋め込みアイテムにカスタム クリップボード形式やリンクなどの高度な OLE 機能の多くをサポートするには、コンボ。
DRAWCLI が OCLIENT と同じようにこのアプリケーション OLE コンテナー サポートを実装します。ただし、既存のオブジェクト指向描画プログラムのウィンドウで実行します。どのように OLE コンテナー サポートを実装し、既存のアプリケーションに統合する方法を示します。
SUPERPAD は、このアプリケーション、またはがスタンドアロン アプリケーションで、 OLE サーバーです。これを実行するサーバーのサポートは、最小主義です。興味のあるデータをクリップボードにコピーするには、 OLE クリップボード サービスを使用するがクリップボードの貼り付けの機能を実行するためにウィンドウの [編集] のコントロールに組み込まれた機能を使用します。これは、新しい OLE API と従来の Windows API を使用するか、統合の興味深いミックスを示します。
サンプル アプリケーションの詳細については、 「MFC サンプル」ヘルプを参照してください。
ケース スタディ: MFC 2.0 からの OCLIENT
上で説明したように、 OCLIENT は、 MFC 2.0 に含まれており、 MFC/OLE1 の OLE を実行します。MFC/OLE 2 のクラスを使用するには、このアプリケーションが最初に変換する手順を次に示します。一部の機能がより効率的に MFC/OLE のクラスを示すために最初のポートが完了した後に追加されました。これらの機能は、ここでは説明しません; これらの高度な機能の詳細については、サンプル自体を参照してください。
[!メモ]
コンパイラ エラーと適切なプロセスは Visual C++ 2.0 で作成されています。特定のと場所は、 Visual C++ 4.0 で変更する概念については有効なままです。
それを実行中に取得します
MFC/OLE に OCLIENT サンプルを移植するのにかかる方法は、アプリケーションをビルドおよび作成されたマニフェスト コンパイラ エラーを修正することです。MFC 2.0 からの OCLIENT サンプルを受け取り、 MFC のこのバージョンでコンパイルする場合、が解決する多くのエラーないことがわかります。順序で発生したエラーは次に示します。
エラーをコンパイルし、変更します。
\oclient\mainview.cpp(104) : error C2660: 'Draw' : function does not take 4 parameters
最初のエラーは COleClientItem::Drawの問題です。MFC/OLE1 では MFC/OLE バージョンはより多くのパラメーターを取りました。補足的なパラメーターは、必要に応じて、通常は null ではなかった点です (この例のように)。MFC のこのバージョンは描画 CDC がメタファイルの DC ときに自動的に lpWBounds の値を調べることができます。また、 pFormatDC パラメーターは、フレームワークが渡された pDC の DC 「属性」から " 1 " をビルドので、必要ではありません。この問題を解決するには、描画の呼び出しに 2 追加の二つの null パラメーターを単に削除します。
\oclient\mainview.cpp(273) : error C2065: 'OLE_MAXNAMESIZE' : undeclared identifier
\oclient\mainview.cpp(273) : error C2057: expected constant expression
\oclient\mainview.cpp(280) : error C2664: 'CreateLinkFromClipboard' : cannot convert parameter 1 from 'char [1]' to 'enum ::tagOLERENDER '
\oclient\mainview.cpp(286) : error C2664: 'CreateFromClipboard' : cannot convert parameter 1 from 'char [1]' to 'enum ::tagOLERENDER '
\oclient\mainview.cpp(288) : error C2664: 'CreateStaticFromClipboard' : cannot convert parameter 1 from 'char [1]' to 'enum ::tagOLERENDER '
すべてが MFC/OLE1 で機能するという事実の結果の上部のエラーは、項目を表す一意の名前が渡されることが必要です。これは、基になる OLE API の必要条件です。これは、 OLE 2 が基の通信の機能として DDE を使用しないため MFC/OLE 2 ではありません (名前は DDE 対話に使用されました)。この問題を解決するには、 CreateNewName の関数を削除したり、オブジェクトへのすべての参照。各 MFC/OLE の関数がこの呼び出しのバージョンにカーソルを置き、 F1 キーを押すと、単に使用するものを検索する方が簡単です。
は大きく異なるもう一つの領域は OLE 2 のクリップボードの処理です。OLE1 を使用すると、ウィンドウを使用して、クリップボードの API によってはクリップボードに対話している。OLE 2 により、別の機能によってされます。MFC/OLE1 API は、クリップボードがクリップボードに対するの COleClientItem のオブジェクトをコピーする前に開かれていたと見なしました。これは不要で、すべての MFC/OLE のクリップボード操作が失敗する。CreateNewNameの依存関係を削除するためのコードを編集するときに、 Windows クリップボードを開閉するコードを削除する必要があります。
\oclient\mainview.cpp(332) : error C2065: 'AfxOleInsertDialog' : undeclared identifier
\oclient\mainview.cpp(332) : error C2064: term does not evaluate to a function
\oclient\mainview.cpp(344) : error C2057: expected constant expression
\oclient\mainview.cpp(347) : error C2039: 'CreateNewObject' : is not a member of 'CRectItem'
CMainView::OnInsertObject ハンドラーからこれらのエラーの結果。「新しい項目を挿入オブジェクト」のコマンドを処理するには、次のビットを大幅に変更した別の領域です。この場合、新しい OLE コンテナー アプリケーションに AppWizard によって提供される値と元の実装をマージする方が簡単です。実際、これは、他のアプリケーションの移植に適用できる手法です。MFC/OLE1 では、 AfxOleInsertDialog 関数を呼び出すことによって挿入 「オブジェクト」ダイアログ ボックスを表示します。このバージョンで COleInsertObject のダイアログ オブジェクトを構築し、 DoModalをダイヤルします。また、新しい OLE アイテムはクラス名の文字列の代わりに CLSID で作成されます。最終結果は次のようなする必要があります。
COleInsertDialog dlg;
if (dlg.DoModal() != IDOK)
return;
BeginWaitCursor();
CRectItem* pItem = NULL;
TRY
{
// First create the C++ object
pItem = GetDocument()->CreateItem();
ASSERT_VALID(pItem);
// Initialize the item from the dialog data.
if (!dlg.CreateItem(pItem))
AfxThrowMemoryException();
// any exception will do
ASSERT_VALID(pItem);
// run the object if appropriate
if (dlg.GetSelectionType() ==
COleInsertDialog::createNewItem)
pItem->DoVerb(OLEIVERB_SHOW, this);
// update right away
pItem->UpdateLink();
pItem->UpdateItemRectFromServer();
// set selection to newly inserted item
SetSelection(pItem);
pItem->Invalidate();
}
CATCH (CException, e)
{
// clean up item
if (pItem != NULL)
GetDocument()->DeleteItem(pItem);
AfxMessageBox(IDP_FAILED_TO_CREATE);
}
END_CATCH
EndWaitCursor();
[!メモ]
新しい項目を挿入のオブジェクトはアプリケーションごとに異なる場合があります):
MFC に用意されている COleInsertObject のダイアログ クラス、またはそのほかの標準ダイアログの宣言を含む <afxodlgs.h>を含むことも必要です。
\oclient\mainview.cpp(367) : error C2065: 'OLEVERB_PRIMARY' : undeclared identifier
\oclient\mainview.cpp(367) : error C2660: 'DoVerb' : function does not take 1 parameters
これらのエラーは OLE1 定数が OLE 2 で変更することによって概念が同じであっても発生します。この場合 OLEVERB_PRIMARY は OLEIVERB_PRIMARYに変更されました。OLE OLE1 と 2 の両方では、主要な動詞は、通常、コンテナーによってユーザーが項目のダブルクリックときに実行されます。
また、 DoVerb は、補足的なパラメーター —ビュー (*CViewへのポインターを受け取ります)。このパラメーターが 「Edit」ビジュアルだけ使用されます (または埋め込み先編集の有効化)を実行できます。ここでは、現時点で、この機能を実装しないので無効にするために、パラメーターを設定します。
次のようにフレームワークが埋め込み先編集の有効化には行わないようにするには、 COleClientItem::CanActivate をオーバーライドする必要があります:
BOOL CRectItem::CanActivate()
{
return FALSE;
}
\oclient\rectitem.cpp(53) : error C2065: 'GetBounds' : undeclared identifier
\oclient\rectitem.cpp(53) : error C2064: term does not evaluate to a function
\oclient\rectitem.cpp(84) : error C2065: 'SetBounds' : undeclared identifier
\oclient\rectitem.cpp(84) : error C2064: term does not evaluate to a function
MFC/OLE1 では、項目の範囲を照会および操作するために、 COleClientItem::GetBounds と SetBounds が使用されました ( Left,左,左揃え と top のメンバーは常にです)。サイズ(&&S),サイズ か CSize を代わりに使用 MFC/OLE 2 では、これは COleClientItem::GetExtent と SetExtentによって直接サポートされます。
新しい SetItemRectToServer のコード、および UpdateItemRectFromServer の呼び出しは次のようになります。:
BOOL CRectItem::UpdateItemRectFromServer()
{
ASSERT(m_bTrackServerSize);
CSize size;
if (!GetExtent(&size))
return FALSE; // blank
// map from HIMETRIC to screen coordinates
{
CClientDC screenDC(NULL);
screenDC.SetMapMode(MM_HIMETRIC);
screenDC.LPtoDP(&size);
}
// just set the item size
if (m_rect.Size() != size)
{
// invalidate the old size/position
Invalidate();
m_rect.right = m_rect.left + size.cx;
m_rect.bottom = m_rect.top + size.cy;
// as well as the new size/position
Invalidate();
}
return TRUE;
}
BOOL CRectItem::SetItemRectToServer()
{
// set the official bounds for the embedded item
CSize size = m_rect.Size();
{
CClientDC screenDC(NULL);
screenDC.SetMapMode(MM_HIMETRIC);
screenDC.DPtoLP(&size);
}
TRY
{
SetExtent(size); // may do a wait
}
CATCH(CException, e)
{
return FALSE; // links will not allow SetBounds
}
END_CATCH
return TRUE;
}
\oclient\frame.cpp(50) : error C2039: 'InWaitForRelease' : is not a member of 'COleClientItem'
\oclient\frame.cpp(50) : error C2065: 'InWaitForRelease' : undeclared identifier
\oclient\frame.cpp(50) : error C2064: term does not evaluate to a function
コンテナーからサーバーへの MFC/OLE1 同期 API 呼び出しでは OLE1 が多くの場合、本来非同期であるため、 シミュレートされています。ユーザーからのコマンドを処理するまでにかなりの非同期呼び出しの処理中を確認する必要がありました。MFC/OLE1 では、そのための COleClientItem::InWaitForRelease 関数を提供します。MFC/OLE 2 では、これは必須ではないので、 CMainFrame OnCommand のオーバーライドをすべて一緒に削除できます。
この時点で OCLIENT はコンパイルおよびリンクします。
そのほかの必要な変更
しかし、実行の OCLIENT を保持する、実行されない少数の点があります。後ではなく、これらの問題をすぐに変更することをお勧めします。
最初に、 OLE ライブラリを初期化する必要があります。これは InitInstanceから AfxOleInit を呼び出すことにより実行されます:
if (!AfxOleInit())
{
AfxMessageBox("Failed to initialize OLE libraries");
return FALSE;
}
また、パラメーター リストの変更の仮想関数をチェックすることをお勧めします。1 個のこのような関数は MFC/OLE コンテナー アプリケーションでオーバーライドされる COleClientItem::OnChangeです。オンライン ヘルプを参照することによって、追加の " ダブルワードの dwParam が追加されたことがわかります。新しい CRectItem::OnChange を次のように記述:
void
CRectItem::OnChange(OLE_NOTIFICATION wNotification, DWORD dwParam)
{
if (m_bTrackServerSize &&
!UpdateItemRectFromServer())
{
// Blank object
if (wNotification == OLE_CLOSED)
{
// no data received for the object - destroy it
ASSERT(!IsVisible());
GetDocument()->DeleteItem(this);
return; // no update (item is gone now)
}
}
if (wNotification != OLE_CLOSED)
Dirty();
Invalidate(); // any change will cause a redraw
}
MFC/OLE1 では、コンテナー アプリケーションは COleClientDocドキュメントからクラスを派生。MFC/OLE 2 でこのクラスは COleDocument と削除され、置き換えられました。この新しい組織は、コンテナー/サーバー アプリケーションをビルドしやすくします)。OCLIENT のような #define が MFC/OLE 2 に MFC/OLE1 アプリケーションの移植を簡略化するために COleDocument に COleClientDoc をマップするあります。COleClientDoc によって提供された COleDocument によって提供されない機能の 1 つが標準コマンド メッセージ マップ エントリです。これは、コンテナー/サーバー アプリケーションでは、 COleDocument を間接的に)使用するサーバー アプリケーションでは、これらのコマンド ハンドラーのオーバーヘッドが提供されないようになります。CMainDoc のメッセージ マップに次のエントリを追加する必要があります:
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdatePasteMenu)
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE_LINK, OnUpdatePasteLinkMenu)
ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_LINKS, OnUpdateEditLinksMenu)
ON_COMMAND(ID_OLE_EDIT_LINKS, COleDocument::OnEditLinks)
ON_UPDATE_COMMAND_UI(ID_OLE_VERB_FIRST, OnUpdateObjectVerbMenu)
ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_CONVERT, OnUpdateObjectVerbMenu)
ON_COMMAND(ID_OLE_EDIT_CONVERT, OnEditConvert)
ドキュメントの基本クラスでこれらすべてのコマンドの実装は COleDocumentにあります。
この時点で、 OCLIENT 機能は OLE コンテナー アプリケーションです。これは、任意の型の項目に挿入できます (OLE1 または OLE 2)。埋め込み先編集の有効化を有効にするために必要なコードが実行されないため、項目は OLE1 のと同じように個別のウィンドウでは編集されます。次のセクションで埋め込み先編集について説明します (ビジュアル編集、 「」という有効にする)必要な変更が。
add 「」をビジュアル編集
OLE の重要な機能の 1 つが埋め込み先編集の有効化 (または 「ビジュアル編集」)。この機能は、ユーザーにコンテナーのユーザー インターフェイスの部分を引き継ぐサーバー アプリケーションが提供されるよりシームレスなインターフェイスを編集できます。OCLIENT に埋め込み先編集の有効化を実行するには、追加のリソースは、追加コードを追加する必要があります。これらのリソースやコードは、 AppWizard によく使用されます。実際、次のコードの大半は、 「」のコンテナー サポートと AppWizard 新しいアプリケーションから直接借りられました。
されない埋め込み先編集の項目がある場合、使用するメニューのリソースを追加する必要があります。Visual C++ で IDR_OCLITYPE のリソースをコピーして、すべてがによってこの追加のメニュー リソースを削除しても作成できますが、コンテナーに存在するファイルとウィンドウのポップアップは例外です。2 個の区分線がコンテナーに存在するファイルの間に挿入され、グループ (示すように、ペインは、などの分離を表示する必要があります:されます。 ファイル | | ペイン)。詳細については、これらの区切り記号であり、と 「メニューとリソースを外観のサーバーとコンテナーのメニューがどのようにマージする方法: OLE 2 クラスのメニューのマージ。
これらのメニューを作成した場合、フレームワークのファイルについて通知する必要があります。これはドキュメント テンプレートの CDocTemplate::SetContainerInfo を呼び出して InitInstance のドキュメント テンプレートの一覧に追加する前になります。ドキュメント テンプレートを登録する新しいコードは次のようになります。:
CDocTemplate* pTemplate = new CMultiDocTemplate(
IDR_OLECLITYPE,
RUNTIME_CLASS(CMainDoc),
RUNTIME_CLASS(CMDIChildWnd), // standard MDI child frame
RUNTIME_CLASS(CMainView));
pTemplate->SetContainerInfo(IDR_OLECLITYPE_INPLACE);
AddDocTemplate(pTemplate);
IDR_OLECLITYPE_INPLACE のリソースは、 Visual C++ で作成された特殊な埋め込みリソースです。
埋め込み先編集の有効化を有効にするには、 CView (CMainView)の派生クラス、または COleClientItem の派生クラスの両方 (CRectItem)で変更する必要がある点があります。これらのオーバーライドはすべて、 AppWizard によって提供され、実装の大部分は、既定の AppWizard アプリケーションから直接取得されます。
このポートの最初に、埋め込み先編集の有効化は、オーバーライドの COleClientItem::CanActivateによって完全に無効になっている。このオーバーライドは、埋め込み先編集の有効化を許可するように削除する必要があります。また、 null は DoVerb へのすべての呼び出しのビューを提供できる埋め込み先編集の有効化にだけであるため、渡された引数 (そのうちの 2 つがあります)。完全に埋め込み先編集の有効化を実行するには、 DoVerb の呼び出しの適切なビューを渡す必要があります。これらの呼び出しの 1 つが CMainView::OnInsertObjectにあります:
pItem->DoVerb(OLEIVERB_SHOW, this);
別のスレッドは CMainView::OnLButtonDblClkにあります:
m_pSelection->DoVerb(OLEIVERB_PRIMARY, this);
COleClientItem::OnGetItemPositionをオーバーライドする必要があります。これは、アクティブにする項目が埋め込み先編集のときにサーバーにコンテナーのペインに関連するウィンドウを配置する場所を示します。OCLIENT では、実装が自明であると見なされる条件:
void CRectItem::OnGetItemPosition(CRect& rPosition)
{
rPosition = m_rect;
}
ほとんどのサーバーでは、 「埋め込み先のサイズ変更」。と呼ばれることを実行しますこれは、ユーザーが項目を編集している間サーバー ペインのサイズ設定され、移動します。コンテナーは、この操作に参加する必要があります。ペインを移動またはサイズを変更することは通常、コンテナー ドキュメント内の位置とサイズ自体に影響します。OCLIENT の実装は、新しい位置とサイズと m_rect によって保持される内部四角形を同期します。
BOOL CRectItem::OnChangeItemPosition(const CRect& rectPos)
{
ASSERT_VALID(this);
if (!COleClientItem::OnChangeItemPosition(rectPos))
return FALSE;
Invalidate();
m_rect = rectPos;
Invalidate();
GetDocument()->SetModifiedFlag();
return TRUE;
}
アクティブなが、コードがユーザーが編集セッションを終了することはできませんこの時点でと、埋め込み先編集をアクティブにするとサイズ変更や項目の移動を処理できるように項目がする完全なコードがあります。あるサーバーこの機能がそれぞれが Esc キーを処理して提供しますが、コンテナーが項目を非アクティブ化、 2 とおりの方法を使用することが推奨されています: 、 (2) Esc キーを押すことによって項目の外側をクリックして (1)。
Esc キーの場合、コマンドに VK_ESCAPE のキーをマップする Visual C++、 ID_CANCEL_EDIT のアクセラレータを追加するリソースに追加します。このコマンドのハンドラーを示します:
// The following command handler provides the standard
// keyboard user interface to cancel an in-place
// editing session.void CMainView::OnCancelEdit()
{
// Close any in-place active item on this view.
COleClientItem* pActiveItem =
GetDocument()->GetInPlaceActiveItem(this);
if (pActiveItem != NULL)
pActiveItem->Close();
ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
}
ユーザーが項目の外側をクリックするケースを処理するために、 CMainView::SetSelectionの先頭に次のコードを追加します:
if (pNewSel != m_pSelection || pNewSel == NULL)
{
COleClientItem* pActiveItem =
GetDocument()->GetInPlaceActiveItem(this);
if (pActiveItem != NULL && pActiveItem != pNewSel)
pActiveItem->Close();
}
項目は埋め込み先編集の場合、フォーカスが必要です。これを確認すると、ビューがフォーカスを受け取ったときにフォーカスがアクティブな項目に常に転送するように、 OnSetFocus を処理する場合です:
// Special handling of OnSetFocus and OnSize are required
// when an object is being edited in-place.
void CMainView::OnSetFocus(CWnd* pOldWnd)
{
COleClientItem* pActiveItem =
GetDocument()->GetInPlaceActiveItem(this);
if (pActiveItem != NULL &&
pActiveItem->GetItemState() == COleClientItem::activeUIState)
{
// need to set focus to this item if it is same view
CWnd* pWnd = pActiveItem->GetInPlaceWindow();
if (pWnd != NULL)
{
pWnd->SetFocus(); // don't call the base class
return;
}
}
CView::OnSetFocus(pOldWnd);
}
ビューがサイズ変更されると、クリッピング四角形が変更され、アクティブな項目を通知する必要があります。これを行うには OnSizeのハンドラーを用意しました:
void CMainView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
COleClientItem* pActiveItem =
GetDocument()->GetInPlaceActiveItem(this);
if (pActiveItem != NULL)
pActiveItem->SetItemRects();
}
ケース スタディ: MFC 2.0 で HIERSVR
HIERSVR は、 MFC 2.0 に含まれており、 MFC/OLE1 の OLE を実行します。ここでは、簡単に MFC/OLE 2 のクラスを使用するには、このアプリケーションが最初に変換する手順について説明します。一部の機能がより効率的に MFC/OLE 2 のクラスを示すために最初のポートが完了した後に追加されました。これらの機能は、ここでは説明しません; これらの高度な機能の詳細については、サンプル自体を参照してください。
[!メモ]
コンパイラ エラーと適切なプロセスは Visual C++ 2.0 で作成されています。特定のと場所は、 Visual C++ 4.0 で変更する概念については有効なままです。
それを実行中に取得します
MFC/OLE に HIERSVR サンプルを移植するのにかかる方法は、アプリケーションをビルドおよび作成されたマニフェスト コンパイラ エラーを修正することです。MFC 2.0 で HIERSVR サンプルを受け取り、 MFC のこのバージョンでコンパイルする (OCLIENT サンプルとの詳細があります)解決する多くのエラーがないことがわかります。通常、出現する順序でエラーは次に示します。
エラーをコンパイルし、変更します。
\hiersvr\hiersvr.cpp(83) : error C2039: 'RunEmbedded' : is not a member of 'COleTemplateServer'
この最初のエラーは、サーバーの InitInstance の関数の、より大きな問題を示します。OLE サーバーに必要な初期化は、その実行を取得するために、 MFC/OLE1 アプリケーションに行う必要がある最も大きな変更の 1 つです。最善は、 AppWizard が OLE サーバーに表示されます。作成する、必要に応じてコードを変更します。注意が必要な点を次に示します。:
AfxOleInitを呼び出して、 OLE ライブラリを初期化する必要があります
CDocTemplate のコンストラクターで設定できない場合はサーバー リソース ハンドルおよびランタイム クラス情報へのドキュメント テンプレート オブジェクトの呼び出し SetServerInfo。
/Embedding がコマンド ラインにあるアプリケーションのメイン ウィンドウが表示されないようにします。
ドキュメントの GUID が必要です。これはドキュメント タイプ (128 ビット)の一意の識別子です。AppWizard、の 1 種類を作成します。新しい AppWizard によって生成されたサーバー アプリケーションから新しいコードをコピーします。ここで説明した手法を使用すると、そのアプリケーションから GUID を 「単に」盗み出すことができます。そうでない場合、 Bin ディレクトリに GUIDGEN.EXE ユーティリティを使用できます。
これは COleTemplateServer::ConnectTemplateを呼び出して、必要 「接続します」ドキュメント テンプレートへの COleTemplateServer のオブジェクトをです。
アプリケーションが実行されたスタンドアロンのときにシステム レジストリを更新します。ユーザーがアプリケーションの .EXE を移動すると新しい場所から実行するこのようにして、新しい場所を指すように Windows のシステム登録データベースを更新します。
基づいてこれらの変更すべてを適用した後で、次のように AppWizard が InitInstanceの InitInstance (および HIERSVR の関連の GUID の場合)を作成するステートメントに読み込む必要があります:
// this is the GUID for HIERSVR documents
static const GUID BASED_CODE clsid =
{ 0xA0A16360L, 0xC19B, 0x101A, { 0x8C, 0xE5, 0x00, 0xDD, 0x01, 0x11, 0x3F, 0x12 } };
/////////////////////////////////////////////////////////////////////////////
// COLEServerApp initialization
BOOL COLEServerApp::InitInstance()
{
// OLE 2 initialization
if (!AfxOleInit())
{
AfxMessageBox("Initialization of the OLE failed!");
return FALSE;
}
// Standard initialization
LoadStdProfileSettings(); // Load standard INI file options
// Register document templates
CDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_HIERSVRTYPE,
RUNTIME_CLASS(CServerDoc),
RUNTIME_CLASS(CMDIChildWnd),
RUNTIME_CLASS(CServerView));
pDocTemplate->SetServerInfo(IDR_HIERSVRTYPE_SRVR_EMB);
AddDocTemplate(pDocTemplate);
// create main MDI Frame window
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd = pMainFrame;
SetDialogBkColor(); // gray look
// enable file manager drag/drop and DDE Execute open
m_pMainWnd->DragAcceptFiles();
EnableShellOpen();
m_server.ConnectTemplate(clsid, pDocTemplate, FALSE);
COleTemplateServer::RegisterAll();
// try to launch as an OLE server
if (RunEmbedded())
{
// "short-circuit" initialization -- run as server!
return TRUE;
}
m_server.UpdateRegistry();
RegisterShellFileTypes();
// not run as OLE server, so show the main window
if (m_lpCmdLine[0] == '\0')
{
// create a new (empty) document
OnFileNew();
}
else
{
// open an existing document
OpenDocumentFile(m_lpCmdLine);
}
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
return TRUE;
}
上のコードが新しいリソース id を示すことで、 IDR_HIERSVRTYPE_SRVR_EMB わかります。これは、コンテナーに埋め込まれているドキュメントを編集するときに使用するメニューのリソースです。MFC/OLE1 で埋め込みアイテムの編集に特定のメニュー項目は実行時に変更されました。まったく違って、メニュー構造を使用して編集することによってこれら二つの異なるモードに異なるユーザー インターフェイスを提供しやすくするコンテナーに存在するファイル ベースのドキュメントを編集する代わりに埋め込みアイテムをです。後で参照するため、完全に別のメニュー リソースが埋め込み埋め込みオブジェクトを編集するときに使用します。
このリソースを作成するには、リソース スクリプトを Visual C++ に読み取り、既存の IDR_HIERSVRTYPE のメニュー リソースをコピーします。IDR_HIERSVRTYPE_SRVR_EMB に新しいリソースの名前を変更します (これは、 AppWizard を使用)同じ名前付け規則です。「コンテナーに存在するファイル更新」に次の変更 「コンテナーに存在するファイル保存」; これに ID_FILE_UPDATEコマンド ID を指定します。「コンテナーに存在するファイル保存コピーに 「コンテナーに存在するファイル名を付けて保存」を」に変更します。; これに ID_FILE_SAVE_COPY_ASコマンド ID を指定します。フレームワークは、両方のコマンドの実装を提供します。
\hiersvr\svritem.h(60) : error C2433: 'OLESTATUS' : 'virtual' not permitted on data declarations
\hiersvr\svritem.h(60) : error C2501: 'OLESTATUS' : missing decl-specifiers
\hiersvr\svritem.h(60) : error C2146: syntax error : missing ';' before identifier 'OnSetData'
\hiersvr\svritem.h(60) : error C2061: syntax error : identifier 'OLECLIPFORMAT'
\hiersvr\svritem.h(60) : error C2501: 'OnSetData' : missing decl-specifiers
OLESTATUS の型を示すため、いくつかのエラーがあります。 OnSetDataのオーバーライドになります。OLESTATUS は、 OLE1 によって返されるエラーです。これは、 OLE 2 の HRESULT に MFC は通常、エラーを含む COleException に HRESULT を変換しますが、変更されています。このような場合、 OnSetData のオーバーライドは不要ではないので、するのが最も簡単です。は、それを削除することです。
\hiersvr\svritem.cpp(30) : error C2660: 'COleServerItem::COleServerItem' : function does not take 1 parameters
COleServerItem のコンストラクターには追加の " BOOL パラメーターを受け取ります。このフラグがメモリ管理が COleServerItem のオブジェクトでの実行方法を決定します。で設定してフレームワークが true に不要な場合には、これらのオブジェクトの削除メモリ管理それを削除することを処理します。HIERSVR は、ネイティブ データの一部として CServerItem の COleServerItem(から派生)オブジェクトを使用するため、 false にこのフラグを設定します。これは HIERSVR が各サーバー項目がいつ削除されたかを判断します。
\hiersvr\svritem.cpp(44) : error C2259: 'CServerItem' : illegal attempt to instantiate abstract class
\hiersvr\svritem.cpp(44) : error C2259: 'CServerItem' : illegal attempt to instantiate abstract class
これらのエラーが意味するため、 " CServerItem でオーバーライドされていない純粋な virtual' 関数があります。多くの場合、これは OnDraw のパラメーター リストが変更されたことによって発生します。次のようにこのエラーを修正するには、 CServerItem::OnDraw を変更します (、 svritem.h の宣言):
BOOL CServerItem::OnDraw(CDC* pDC, CSize& rSize)
{
// request from OLE to draw node
pDC->SetMapMode(MM_TEXT); // always in pixels
return DoDraw(pDC, CPoint(0,0), FALSE);
}
新しいパラメーター " rSize です。これは便利で描画サイズを設定することができます。このサイズは HIMETRICにある必要があります。この場合、この値を設定することが簡単ではありません。したがって、フレームワークは範囲を取得するに OnGetExtent をダイヤルします。動作させるために OnGetExtentを実行する必要があります:
BOOL CServerItem::OnGetExtent(DVASPECT dwDrawAspect, CSize& rSize)
{
if (dwDrawAspect != DVASPECT_CONTENT)
return COleServerItem::OnGetExtent(dwDrawAspect, rSize);
rSize = CalcNodeSize();
return TRUE;
}
\hiersvr\svritem.cpp(104) : error C2065: 'm_rectBounds' : undeclared identifier
\hiersvr\svritem.cpp(104) : error C2228: left of '.SetRect' must have class/struct/union type
\hiersvr\svritem.cpp(106) : error C2664: 'void __pascal __far DPtoLP(struct ::tagPOINT __far *,int )__far const ' : cannot convert parameter 1 from 'int __far *' to 'struct ::tagPOINT __far *'
CServerItem::CalcNodeSize 関数で項目のサイズは HIMETRIC に変換され、 m_rectBoundsに格納されます。COleServerItem " "m_rectBoundsの非公開メンバーが存在しません (これは m_sizeExtentで部分的に置き換えられましたが、 OLE 2 で m_rectBounds が OLE1 にした)、このメンバーは若干異なる使用があります。このメンバー変数に HIMETRIC のサイズを設定する代わりに、それを返します。この戻り値は、前に実行した OnGetExtentで使用されます。
CSize CServerItem::CalcNodeSize()
{
CClientDC dcScreen(NULL);
m_sizeNode = dcScreen.GetTextExtent(m_strDescription,
m_strDescription.GetLength());
m_sizeNode += CSize(CX_INSET * 2, CY_INSET * 2);
// set suggested HIMETRIC size
CSize size(m_sizeNode.cx, m_sizeNode.cy);
dcScreen.SetMapMode(MM_HIMETRIC);
dcScreen.DPtoLP(&size);
return size;
}
CServerItem は、 COleServerItem::OnGetTextDataをオーバーライドします。この関数は MFC/OLE で互換性のために残されていますが、別の機能に置き換えられます。MFC OLE HIERSVR サンプルの MFC バージョン 3.0 はオーバーライドの COleServerItem::OnRenderFileDataして、この機能を実装します。この機能は、この基本的なポートにとって重要ではないので、 OnGetTextData のオーバーライドを削除できます。
アドレス指定されていない svritem.cpp に多くのエラーがあります。これらは 「実際のエラーです —」以前のエラーが発生している、エラーではありません。
\hiersvr\svrview.cpp(325) : error C2660: 'CopyToClipboard' : function does not take 2 parameters
COleServerItem::CopyToClipboard は、 " bIncludeNative のフラグをサポートしません。ネイティブ データ (サーバー項目によって書き出されるデータは関数をシリアル化します)、削除する最初のパラメーターを常にコピーします。また、 CopyToClipboard はエラーが false を返す代わりに発生する例外をスローします。次のよう CServerView::OnEditCopy のコードを変更する:
void CServerView::OnEditCopy()
{
if (m_pSelectedNode == NULL)
AfxThrowNotSupportedException();
TRY
{
m_pSelectedNode->CopyToClipboard(TRUE);
}
CATCH_ALL(e)
{
AfxMessageBox("Copy to clipboard failed");
}
END_CATCH_ALL
}
OCLIENT の同じバージョン用のより詳細なエラーがあったが HIERSVR の MFC Version 2.0 のコンパイルに作成されますが、実際にはいくつかの変更がありました。
この時点で HIERSVR は、 OLE サーバーとして、次に実行される埋め込み先編集機能なしでコンパイルし、がリンクし、作用します。
add 「」をビジュアル編集
このビジュアル編集サーバー アプリケーションに 「」 (または埋め込み先編集の有効化)を追加するには、大事にする必要があるいくつかの作業だけです:
項目が埋め込み先編集のときに特別なメニュー リソースを使用する必要があります。
このアプリケーションにツールバーがあるため、正常なツールバーのサブセットだけを含むツールバーがサーバー上 (一致するメニューのリソース)から使用できるメニュー コマンドと一致する必要があります。
埋め込み先のユーザー インターフェイスを提供する COleIPFrameWnd から派生した新しいクラスを必要とします ( CMDIFrameWndから派生した CMainFrame と同じように、 MDI のユーザー インターフェイスを提供します)。
これらの特殊なリソースやクラスに関するフレームワークを指定する必要があります。
メニュー リソースが作成が簡単になります。Visual C++ を実装し、 IDR_HIERSVRTYPE_SRVR_IP というメニュー リソースにメニュー リソース IDR_HIERSVRTYPE をコピーします。編集する場合と、ヘルプのポップアップ メニューが残っているようにメニューを変更します。編集およびヘルプ (メニューの例を次の間のメニューに 2 個の区切り記号を表示する必要があります。追加します: 編集 | | ヘルプなど)。およびの詳細については、サーバーとコンテナーのメニューがどのようにマージするか、これらの区切り記号の平均は、 「メニューとリソースを参照したり、: OLE 2 クラスのメニューのマージ。
サブセットをツールバーのビットマップがチェックされる 「server」オプションと新しい AppWizard によって生成されるアプリケーションからの 1 種類をコピーして簡単に作成できます。このビットマップは、 Visual C++ にインポートできます。ビットマップに IDR_HIERSVRTYPE_SRVR_IP の ID を与えることを確認します。
サーバー サポートする AppWizard によって生成されるアプリケーションから COleIPFrameWnd から派生したクラスは、コピーできます。両方のファイル、 IPFRAME.CPP と IPFRAME.H をコピーし、プロジェクトに追加します。前の手順をことで作成されたビットマップを LoadBitmap の呼び出し参照する IDR_HIERSVRTYPE_SRVR_IP 確認します。
すべての新しいリソースやクラスが作成されたので、このアプリケーションは、埋め込み先編集をサポートすることは)は、フレームワークがこれらを認識するようにコードを追加します (と対応しています。これは InitInstance の関数の SetServerInfo の呼び出しにいくつかのパラメーターを追加することにより実行されます:
pDocTemplate->SetServerInfo(IDR_HIERSVRTYPE_SRVR_EMB,
IDR_HIERSVRTYPE_SRVR_IP, RUNTIME_CLASS(CInPlaceFrame));
これには、または埋め込み先編集の有効化をサポートする任意のコンテナーの実行可能な埋め込みです。ただし、現在でもコードに潜んでいる第 1 のわずかなバグがあります。HIERSVR は、ユーザーが右ボタンを押すと表示されるコンテキスト メニューをサポートします。このメニューは埋め込み埋め込むことを編集すると HIERSVR が完全に開かれますが働きましたりと、機能しません。原因は CServerView::OnRButtonDown のこの一つのコード行に固定できます:
pMenu->TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
point.x, point.y, AfxGetApp()->m_pMainWnd);
AfxGetApp()->m_pMainWndへの参照に注意してください。サーバーが埋め込み先編集をアクティブにすると、メイン ウィンドウがあり、 m_pMainWnd が設定されますが、通常は非表示になります。また、このウィンドウは、スタンドアロン サーバーが完全に開いているか実行されている場合にアプリケーションの メイン ウィンドウ 、表示される MDI フレーム ウィンドウが表示されます。これは、埋め込み先とのアクティブ化 COleIPFrameWndから派生したフレーム ウィンドウであるアクティブなフレーム ウィンドウは表示されません。埋め込み先編集が、 MFC のこのバージョンの新しい関数を追加する場合でも、正しいアクティブ ウィンドウ、 AfxGetMainWndを取得する。通常、 AfxGetApp()->m_pMainWndの代わりに使用する必要があります。このコードは次のように変更する必要があります:
pMenu->TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
point.x, point.y, AfxGetMainWnd());
現在最小限に機能埋め込み先編集の有効化に対して有効である OLE サーバーがあります。ただし、 MFC/OLE1 の存在しない MFC/OLE 2 で使用できる多くの機能があります。実行する場合がある機能の概念については HIERSVR サンプルを参照してください。HIERSVR の実装を以下に示します。一部の機能:
これは、コンテナーに対して true WYSISYG の動作に拡大されます。
ドラッグ/ドロップおよびカスタム クリップボード形式。
選択としてコンテナーのウィンドウをスクロールすると、変更されます。
MFC 3.0 の HIERSVR サンプルでは、サーバー項目に少し異なるデザインを使用します。これはのメモリを節約し、リンクを高めることが広くなります。HIERSVR の 2.0 バージョンはツリー is-aCOleServerItemの各ノード。COleServerItem は、これらのノードの横に不可欠である、 COleServerItem は、アクティブなリンクに必要ですよりもオーバーヘッドが少なくて済みます。しかし、非常にいつでもいくつかのアクティブなリンクがあります。この効率的に行うには、 MFC のこのバージョンのは HIERSVR COleServerItemからノードを区切ります。これに CServerNode と CServerItem のクラスの両方があります。CServerItem ( COleServerItemから派生)必要に応じてのみ作成されます。特定のノードへの特定リンクを使用してコンテナー ()中止が、 CServerNode に関連付けられている CServerItem のオブジェクト削除されます。このデザインは効率と柔軟性があります。この柔軟性は複数選択リンクを扱う際になっています。COleServerItem がネイティブ データから切り離されているため、 HIERSVR は複数選択の二つのバージョンのいずれも、ただし、 HIERSVR の MFC バージョン 3.0 と (およびそのような選択に対するサポートにリンク)を追加し、判断するのはです。