MFC   VC++   Visual Studio   Visual Studio   プログラミング

2008 sp1での実行ファイルサイズ

 Visual Studio 2008 sp1でMFCを使い、「スタティックライブラリでMFCを使う」にした場合、プロジェクトを作って何もしないまま実行ファイルを作るとファイルサイズが大きくなる。
 特にドキュメントを使用し、リボンコントロールを使用したり、視覚スタイルの切り替えを有効にすると、それだけで約3Mにもなる。

 ここで、何がそんなに容量を増やしているか調べてみたところ、Office 2008用のリソースにデザイン用のPNG画像が大量にあることがわかりました。
 具体的には、PNG画像は485個で745,894バイトもありました。
 一つ一つはそれ程大きくないのですが、数が多いためこのサイズになっています。

 そこで、ちょっとでもサイズを小さくしたい場合、視覚テーマをOffice 2008以外のものにし、切り替えを無効にするか、Office 2008タイプは使用しないようにします。
 当然、リボンコントロールは使用しないようにします。
 ちなみに、「Visual Studio 2005」や「Office 2003」「Office XP」などではPNGは使われておらず、ビットマップだけで、それ程サイズも大きくないのでここでは無視します。

 しかし、この方法でも内部で勝手にリソースを入れるようにコンパイルされるので、そのままでは結局同じファイルサイズになってしまいます。
 そこで、ちょっとイレギュラーなやり方かもしれませんが、リソースファイルを編集してしまいます。

 視覚テーマが定義されているファイルは「afxribbon.rc」で、「〜\Microsoft Visual Studio 9.0\VC\atlmfc\include\l.jpn」にあります。
 このファイルの先頭付近に、
#ifndef _AFX_INTL_RESOURCES
#include "res\RibbonStyle2007Aqua.rc2"
#include "res\RibbonStyle2007Black.rc2"
#include "res\RibbonStyle2007Blue.rc2"
#include "res\RibbonStyle2007Silver.rc2"
#endif
 というのがあり、ここでPNGなどのテーマ用リソースを取り込むように定義されている「rc2」ファイルをインクルードするようになっています。
 そこで、以下のように、独自の定義値「_MYDEF_NO_2007STYLE」が定義されていたらインクルードしないようにします。
#ifndef _AFX_INTL_RESOURCES
#ifndef _MYDEF_NO_2007STYLE
#include "res\RibbonStyle2007Aqua.rc2"
#include "res\RibbonStyle2007Black.rc2"
#include "res\RibbonStyle2007Blue.rc2"
#include "res\RibbonStyle2007Silver.rc2"
#endif
#endif
 後は、「XXX.rc2」内、
// 手動で編集されたりソースをここに追加します...
以下に
#define _MYDEF_NO_2007STYLE
 としておけば、これらのスタイルは取り込まれなくなり、ファイルサイズが約800kb小さくなります。
 この他に、「XXX.rc」内で定義しても良いです。要するに「afxribbon.rc」をインクルードする前に宣言できればいいです。

 ここで、「afxribbon.rc」をインクルードしなければいいのでは?と思うかもしれませんが、この中にはツールバーのカスタマイズ用のリソースなどもあり、場合によっては必要になることもあるため、ここではOffice 2008のものだけ除外するようにしてあります。
ランキングへ     posted by 遠雷 | Comment(0) | MFC

ステータスバーにコントロールの説明を表示 その2

 前回の「ステータスバーにコントロールの説明を表示」とは別の方法です。
 前回は「CToolTipCtrl」から派生させてそこに処理を書きましたが、今回はステータスバーのあるクラス(ここではダイアログ)で処理します。

 まず、ヘッダ内(XXXDlg.h)で、
    afx_msg void OnTtnTooltipShow(NMHDR *pNMHDR, LRESULT *pResult);
    afx_msg void OnTtnTooltipPop(NMHDR *pNMHDR, LRESULT *pResult);
と宣言し、ソース内(XXXDlg.cpp)のメッセージマップに、
BEGIN_MESSAGE_MAP(CXXXDlg, CDialog)
    ON_NOTIFY(TTN_SHOW, 0, &CXXXDlg::OnTtnTooltipShow)    // コントロールIDは「0」にする。
    ON_NOTIFY(TTN_POP, 0, &CXXXDlg::OnTtnTooltipPop)
END_MESSAGE_MAP()
 と入力し、後は前回と同じようにリソースのString Tableに必要な文字列を入力し、各関数内で処理をさせます。
 ただし、今回はステータスバーと同じクラスなので、直接文字列をセットできます。
void CXXXDlg::OnTtnTooltipShow(NMHDR *pNMHDR, LRESULT *pResult)
{
    UINT nID = ::GetDlgCtrlID((HWND)pNMHDR->idFrom);    // ウインドウハンドルからコントロールIDを取得

    CString str;
    if(str.LoadString(nID))        // コントロールIDに対応する文字列をリソースから読み取る
        m_wndStatus.SetPaneText(0, str);        // ステータスバーの表示したい位置にテキストをセットする

     *pResult = 0;
}

void CXXXDlg::OnTtnTooltipPop(NMHDR *pNMHDR, LRESULT *pResult)
{
    m_wndStatus.SetPaneText(0, _T("レディ"));        // ここでは「レディ」に戻します。

    *pResult = 0;
}
 前回の方法に比べ今回の方法は、
 ツールチップコントロールに他の処理もさせる場合は前回の派生させる方法で良いかもしれませんが、この処理だけならステータスバーと同じクラスに処理を書く今回の方法が記述的には楽かもしれません。
ランキングへ     posted by 遠雷 | Comment(0) | MFC

ステータスバーにコントロールの説明を表示

 ダイアログなどにステータスバーを設置し、コントロールの説明をツールチップ表示と同時にステータスバーにも表示させる方法です。

 まず、「CToolTipCtrl」から派生させたツールチップコントロール(ここでは「CMyToolTipCtrl」)を作成し、通常通り各コントロールに対応する文字列を「AddTool」で作成する。

 次に、派生させたクラスで「TTN_SHOW」と「TTN_POP」のメッセージを処理するようにする。
 ここで、「TTN_SHOW」はツールチップを表示するとき、「TTN_POP」はツールチップが非表示になるときに呼ばれるメッセージです。

 ツールチップが表示されるとき、ステータスバーにも説明などの文字列を表示させるには、あらかじめリソースのString Tableで、該当コントロールIDに文字列を設定しておく。
void CMyToolTipCtrl::OnTtnTooltipShow(NMHDR *pNMHDR, LRESULT *pResult)
{
    UINT nID = ::GetDlgCtrlID((HWND)pNMHDR->idFrom);    // ウインドウハンドルからコントロールIDを取得

    CXXXDlg* pDlg = (CXXXDlg*)GetParent();    // 親ダイアログへのポインタを取得

    CString str;
    if(str.LoadString(nID))        // コントロールIDに対応する文字列をリソースから読み取る
        pDlg->m_wndStatus.SetPaneText(0, str);
       // ステータスバーの表示したい位置にテキストをセットする

     *pResult = 0;
}
 以上のようにすると、ツールチップが表示されるとと同時にステータスバーにも説明が表示されるようになります。

 しかし、このままではツールチップが消えても、元の説明が残ったままになるので、ツールチップが消えるタイミングでこの文字列を変更・削除するために、
void CMyToolTipCtrl::OnTtnTooltipPop(NMHDR *pNMHDR, LRESULT *pResult)
{
    CXXXDlg* pDlg = (CXXXDlg*)GetParent();
    pDlg->m_wndStatus.SetPaneText(0, _T("レディ"));        // ここでは「レディ」に戻します。

    *pResult = 0;
}
 とします。

 以上のような感じになるのですが、わかりやすくするため、ここではステータスバーに直接文字列をセットしていますが、ステータスバーをpublic以外にして、文字列セット用の関数を用意した方がよいでしょう。

 ちなみに、最初に「AddTool」するとき、文字列を空文字にすると「TTN_SHOW」は呼ばれません。

 別の方法を次に掲載します。
ランキングへ     posted by 遠雷 | Comment(0) | MFC