いやはや、またまたタフなここ数日です。Listen, the story is this....

 

1.C#学習

最初は(C++との同一性や類似性故に)戸惑いを覚えてきた「高級言語C#の差異」ですが、C(++)文法に準えたVisual Basicと割り切って、最近は楽しくプログラミング出来てきました。

未だ「猫でも」のフォーム編をすべてカバーしておりませんが、並行して(今後絶対に必要となる)「埋め込み用リソースファイル(*.resourcesファイル)作成ツール」をまたまた自作しようと、「全て手書きとMSCompAssだけ」で開発を始めました。(要すれば、最終仕様も煮詰まっておらず、すべてが試行錯誤と学習の実習といえます。)

(注)

注:Microsoftは既にresgen.exeというプログラムを持っているので、「ロスジェネ」に準えて「ResGene」にしてみました。

 

2.MSCompAss Version 1.4

そんなこんなで、今後埋め込みリソースの為に"*.resources"ファイルを多用しなければならないのですが、csc.exeコンパイラーの"/resources:"オプションと、プログラムアイコンを指定する"/win32icon:"オプションが、現在のMSConpAssでは一緒には使えません。これを改良しなければならない、ということでMSCompAssのオプションダイアログを変更してVersion 1.4を作ったのですが、完成テストを行っていていくつか改良点が目についてしまいました。

そしてその中の致命的なものが、「ソースファイルパス名のツールチップが(複数のソースファイルを読み込むと)複数発生するという問題」でした。(注)

注:元々ToolTip(Tool Hint Control)は親ウィンドウのコントロールで兄弟のツール(コントロール)の仕様に関わる説明を行うものであり、今までは設定したツールチップのメッセージ文字列を変更する必要が無かったので単なる関数としてヘッダーファイルにして使っていました。今回も(何も考えずに)ソースファイルを読み込む度に、単純にツールチップ作成関数を呼ぶ形にしていましたが、(当たり前ですが)関数を呼ぶたびにどんどんとツールチップ(コントロール)を作ることになるので、(恥ずかしながら)ツールチップが増えてゆく(?)という異常事態になりました。

 

「BCCSkelton(およびそのUnicode版のECCSkelton)を使っていてこんな杜撰なことをしていてはだめだ。きちんとクラス化して使おう!」と思い、本日CTTIPクラスとして、先ずBCCSkelton用のSJIS(ANSI)版を書いて、それをECCSkelton用のUnicode版に落として動作試験をいたしました。そうしたら...

ツールチップが出ねえじゃんかよぅ!(泣;)

 

3.CTTIP(コードは末尾参照)

CTTIPのメソッド、じゃないメンバー関数テスト用のBCCSkeltonプログラムをSkweltonWizard→BCC2ECCでECCSkelton用にコンバートし、順調にスケルトンが動作することを確認して、CTTIPのテストコードを書き込んでゆきました。テストは、ダイアログで、以下CTTIPの関数

(1)ツールチップの付与
(2)ツールチップ文字列の更新
(3)ツールチップ最大幅設定
(4)ツールチップ背景色設定
(5)ツールチップ背景色設定
(6)フォント設定(直接指定)

のテストを行うものですが、初期的なタイプミス等のゴミ掃除を終わってコンパイルが正常に終了して、起動しても「ん?」全くツールチップが現れません。(実際、本当のバグって、エラーが発生しない場合、原因追及がとても困難になるんですよね。)

色々調べ、色々と調整したり、トラップをかけてみてもダメ。

「では」、ということで試しに今まで正常に動いていた「関数版のツールチップ」を導入したのですが、これも表示されません。

途方に暮れながらも様々なキーワードでサイトを調べまくり、とうとう、

(英語)https://social.msdn.microsoft.com/Forums/en-US/5cc9a772-5174-4180-a1ca-173dc81886d9/adding-tooltip-controls-in-unicode-fails?forum=vclanguage
(日本語)https://www.petitmonte.com/bbs/answers?question_id=12982

という関連2記事を発見。

結局、OSとcmmctrl32.dllのバージョンに関わるヘッダーファイルの定義による問題のようです。(注)

注:「ようです」というのは、私もよく分かっていないからです。ANSI版のTOOLINFOA構造体とUNICODE版のTOOLINFOW構造体は共に定義でWindows NT系のバージョン5.00以降(2000年のWindows 2000以降)については、旧TOOLINFO構造体のしっぽに"LPVOID*"(void *lpReserved;)が一つ追加されていることが原因のようです。ANSI版のsizeof(TOOLINFOA)とUnicode版のsizeof(TOOLINFOW)は共に48バイトで同じサイズであり、ANSI版では"sizeof(TOOLINFO)"で問題なく動くのですが、Unicode版ではわざわざ"sizeof(TOOLINFOW) - sizeof(void*)"として"LPVOID*"分を割愛してやらないと正常には動かないのです。(Unicode版のDLLがヘッダーファイルと不整合?)いずれにしても「くそMicrosoft、Docsの中に何か書けよ!(TOOLINFOのAとWの差を調べようと思っても、TOOLINFOWはTOOLINFOAのコピーでLPSTRをLPWSTRにも変更していません!!!)」と毒づきたくなりました。

とはいえ、この変更を行って祈るような気持ちでコンパイルして、実行ファイルをダブルクリックして...

背景色変更()、文字色変更()、テキスト変更、フォント変更(12ptのMS 明朝)と全て正しく実行されました。

 

さぁ、今晩も(慢性膵炎の疑い、なんて心配しないで)ガンガンのむぞー!

 

という気分ですね。

 

【ご参考】

///////////////////////////////////////
// ECCSkelton
// ツールチップクラスCTTIP定義ファイル
// Copyright (c) November, 2022
//        By Ysama
///////////////////////////////////////

class CTTIP
{
public:
    HWND m_hTip;                                //ツールチップのウィンドウハンドル
    HWND m_hParent;                                //親のウィンドウハンドル
    HWND m_hCtrl;                                //コントロールのウィンドウハンドル
    HINSTANCE m_hInstance;                        //親のインスタンス
    TOOLINFOW m_ToolInfo;                        //TOOLINFO構造体
    CFONT m_hFont;                                //ツールチップのフォント
public:        //メンバー関数
    bool SetToolTip(HWND, int, LPWSTR, bool);    //ツールチップの付与
    void UpdateText(LPWSTR);                    //ツールチップ文字列の更新
    void SetWidth(int);                            //ツールチップ最大幅設定
    void SetBackColor(UINT);                    //ツールチップ背景色設定
    void SetTextColor(UINT);                    //ツールチップ背景色設定
    void SetFont(int, LPWSTR);                    //フォント設定(直接指定)
};

//ツールチップの付与
bool CTTIP::SetToolTip(HWND hWnd, int CtrlID, LPWSTR pszText, bool baloon = FALSE) {

    //セットするコントロールの親、IDまたは文字列がNULLの場合エラー扱いとする
    if(!CtrlID || !(m_hParent = hWnd) || !*pszText)
        return FALSE;
    //バルーン型にするか否か
    DWORD style;
    if(baloon)
        style = WS_POPUP | TTS_ALWAYSTIP | TTS_BALLOON;
    else
        style = WS_POPUP | TTS_ALWAYSTIP;
    //対象コントロールのハンドルを取得する
    m_hCtrl = GetDlgItem(m_hParent, CtrlID);
    //文字列リソースのある親ウィンドウ(ダイアログ)のインスタンス
    m_hInstance = (HINSTANCE)GetWindowLong(m_hParent, GWL_HINSTANCE);
    //ツールチップの作成
    m_hTip = CreateWindowExW(NULL, TOOLTIPS_CLASS, NULL, style,
                CW_USEDEFAULT, CW_USEDEFAULT,
                CW_USEDEFAULT, CW_USEDEFAULT,
                m_hParent, NULL, m_hInstance, NULL);
    //ツールチップ作成失敗エラー
    if(!m_hCtrl || !m_hTip)
        return FALSE;
    //ツールチップをコントロールに関連付ける
    ZeroMemory(&m_ToolInfo, sizeof(m_ToolInfo));    //ゼロクリアー
    m_ToolInfo.cbSize = sizeof(TOOLINFOW) - sizeof(void*);
//    m_ToolInfo.cbSize = sizeof(TOOLINFOW);        //Microsoftのバグ?
//(英語)https://social.msdn.microsoft.com/Forums/en-US/5cc9a772-5174-4180-a1ca-173dc81886d9/adding-tooltip-controls-in-unicode-fails?forum=vclanguage
//(日本語)https://www.petitmonte.com/bbs/answers?question_id=12982

    m_ToolInfo.hwnd = m_hParent;
    m_ToolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
    m_ToolInfo.uId = (UINT_PTR)m_hCtrl;
    m_ToolInfo.hinst = m_hInstance;
    m_ToolInfo.lpszText = pszText;
    SendMessage(m_hTip, TTM_ADDTOOL, 0, (LPARAM)&m_ToolInfo);
    SetWindowPos(m_hTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
    return TRUE;
}

//ツールチップ文字列の更新
void CTTIP::UpdateText(LPWSTR pszText) {

    //TOOLINFOの準備
    ZeroMemory(&m_ToolInfo, sizeof(m_ToolInfo));    //ゼロクリアー
    m_ToolInfo.cbSize =  sizeof(TOOLINFOW) - sizeof(void*);
    m_ToolInfo.hwnd = m_hParent;
    m_ToolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
    m_ToolInfo.uId = (UINT_PTR)m_hCtrl;
    m_ToolInfo.hinst = m_hInstance;
    m_ToolInfo.lpszText = pszText;
    SendMessage(m_hTip, TTM_UPDATETIPTEXT, 0, (LPARAM)&m_ToolInfo);
}

//ツールチップ最大幅設定
void CTTIP::SetWidth(int size) {    //任意の幅を許可する場合は size == -1

    SendMessageW(m_hTip, TTM_SETMAXTIPWIDTH, 0, (LPARAM)size);
}

//ツールチップ背景色設定
void CTTIP::SetBackColor(UINT col) {    //任意の幅を許可する場合は size == -1

    SendMessageW(m_hTip, TTM_SETTIPBKCOLOR, col, 0);
}

//ツールチップ背景色設定
void CTTIP::SetTextColor(UINT col) {    //任意の幅を許可する場合は size == -1

    SendMessageW(m_hTip, TTM_SETTIPTEXTCOLOR, col, 0);
}

// フォント設定(直接指定)
void CTTIP::SetFont(int size, LPWSTR FontName) {

    m_hFont.SetFont(m_hTip, size, FontName);
}