VisualStudio2015 Visual C++ を使っている。

 クラスビューで、クラスウィザードを開こうとすると、

 

致命的エラー

「 HRESULT からの例外 0x8ce0000b 」

 

なんて警告が出て、開けない。

 過去にも何度かあり、そのたびにプロジェクトごと作り直していた。

 

 今回、解決方法を発見。

 

 まずは、リンク。

https://topic.alibabacloud.com/a/vs2013-class-wizard-exception-from-hresult0x8ce0000b-workaround_8_8_10248805.html

 

英語ですが・・・。

ここに答え。

I ' ve had the same error when trying to use the Class Wizard. I have reset my environment as described and the error is gone. After this I reconfigured the environment step by step to fit my needs. I noticed that the error appears if I choose to disable external dependency folders (Options\text editor\c/c++\advanced) . Setting the value to true and reopening the solution cleared the error.

 

-----------------------------------------------------------------------------

 VisualStudio2015で、以下の手順(上記の赤い部分)。

-----------------------------------------------------------------------------

「オプション」を開く

→「テキストエディター」

→「C/C++」

→「詳細設定」

→右側の項目の中で

 「データベースの再作成」を「true」に変更

→OKを押す

→再起動(VisualStudio2015の再起動)

 

 これで、データベースが再作成される。

 オプション設定の中の「データベース再作成」は自動的に fakse に戻ってしまうらしいけど、要確認。

 

 これで、クラスウィザードが正常に戻ります。

 画像の描画やスクロールで、画面が白く光ってちらつく。

 

 画面更新の度に、背景を毎回塗り潰しているから、という単純な理由。

 消さないと、そこに残像が残るから。

 

 更新の激しい動作(たとえば画像のスクロール)だと、目が悪くなりそうな「ちらつき」。

 

 で、対策方法はいくつかある。

 

 すごくシンプル(ただし簡単ではない)なのは、背景を消去しない

 メッセージ WM_ERASEBKGND で、塗り潰しを無効にしてしまう。

 若い頃からMFC使ってしまっているから、これを無効にするか迷うことはある。

 ただし、全ての領域を過不足なく再描画してあげないと、残像が残る。

 そこを、どれだけケアできるか。

 画像一枚を貼り付けているだけなら、問題ないのだが。

 

 有名なのは、ダブルバッファリング

 画像をどこか裏で作っておいて、とにかく関数 BitBlt() で転送だけを OnPaint() 関数内で行う。

 転送は高速だから、実用的である。

 仕組みを理解し、裏でビットマップなどを作っておく必要がある。メモリDCとか作って。

 

 MFCだと、スタティックコントロール CStatic にビットマップを割り当てる方法がある。

 SS_BITMAP 属性を割り当てておき、ビットマップハンドルを指定すれば自動的に表示してくれるし、再描画も全てまかせておける。

 ただし、こいつが背景消去を勝手にやってしまい、ちらつきが起こって克服できない。

 

 なので、OnPaint()の中で転送するしかない。

 

// 描画 //
class CDialog*** : public CDialogEx
{

    CBitmap* m_pBitmap ; ※メモリ確保は各自行う

};

void CDialog***::OnPaint()
{
    CPaintDC dc(this); // device context for painting
                       // TODO: ここにメッセージ ハンドラー コードを追加します。
                       // 描画メッセージで TComDialogChild::OnPaint() を呼び出さないでください。

 

    // 1. ビットマップのサイズ //
    CSize sizeBitmap = ※ m_pBitmapのサイズを取得

    ※ またはウィンドウのサイズを取得するのもOK


    // 2. 転送 //
    dc に、ビットマップの内容を転送

}

 

 こんな流れ。

 不親切だけど、ビットマップサイズの取得とか、転送とか、基本的な技術は割愛。そこから説明するとなると、長くなるから。

DIBのクラスを自作する。

これは、検索すれば、すぐサンプルは出てくる。

まずは、COLORREF対応のみ。

 

ビットマップハンドル HBITMAP から DIB を作成するのは、以下の関数。

 

---------------------------------------------------------------------------

    DDB (CDC , CBitmap 等)  → DIB (BYTE配列) 変換
    GetDIBits() : 指定されたビットマップのビットを取得し、指定された形式でバッファにコピー
    int GetDIBits(
      HDC           hdc        , // デバイスコンテキストのハンドル
      HBITMAP       hbmp       , // ビットマップのハンドル
      UINT          uStartScan , // 取得対象の最初の走査行
      UINT          cScanLines , // 取得対象の走査行の数
      LPVOID        lpvBits    , // ビットマップのビットからなる配列
      LPBITMAPINFO  lpbi       , // ビットマップデータのバッファ
      UINT          uUsage       // RGB とパレットインデックスのどちらか
    );

    戻り値 : 関数が成功すると、コピーされた走査行の数が返ります。
----------------------------------------------------------------------------

 

BYTE 配列のサイズ計算とか、確保とか、メモリ破棄とか、それもあるんだけれど。

 

全部書いていると、ブログでは書ききれないし、参考にならない。

 

透過設定は、後で付け加える。最初から32ビットで作成すると、HBITMAPと連係できない。