MFC拡張DLLのダイアログ内のリソースID

[戻る]
いしだ 2011/09/20(火) 14:03:50
http://rarara.cafe.coocan.jp/cgi-bin/lng/vc/vclng.cgi?print+200710/07100020.txt
以前「MFC拡張DLLのリソースID」という質問をさせていただいたのですが、
これに関連した質問をさせていただきます。

拡張DLL内のダイアログや文字列などのリソースは、
プロジェクトをまたいでIDを管理する必要があることは理解しているのですが、
ダイアログ内の各コントロールのIDもその必要があるのでしょうか?

コントロールのIDも一意に割り振っていたのですが、
これらはダイアログ内でのIDですし、
そのダイアログ内でIDが正しく割り振られていれば、
プロジェクト間で一意になっている必要は無いのかなと思ったのですが。

試しにいくつか意図的にIDを被らせても、特に問題無く表示されるのですが、
どなたかIDが被ったせいで問題に遭われたかたはいらっしゃいますでしょうか。

仲澤@失業者 2011/09/27(火) 10:28:46
れす付きませんねぇ。
そもそもウインドウに付いているIDとは、何のためにあるのかを
考えると、良いかもしれません。

実際のところこのIDはWM_COMMANDのコマンドID以外にはほとんど
使われないことがわかります。また逆に、WM_COMMANDでは付随する
LPARAM(=HWND)の方は、まったくと言って良いほど使用されません。
もちろん、IDと報告コード(HIWORD(WPARAM))がわかれば十分なのですが、
そのような仕組みになっている理由は、コマンド分岐コードと
そのコマンドを発行した実オブジェクト(HWND)を分離したいためです。

IDは、もちろん子ウインドウのHWNDの取得、又はCWndオブジェクトの
バインドに使用しますが、それができるのはIDとそのコントロールの
役割を知っている者(そのアプリのプログラマ)だけの特権です。
逆に言うと、それがわかっていない者(OSを含む)はIDが取得できたところで、
ほとんど何もできないと予測できます。

従って、IDについて重要な点とは、

 1.自アプリのコマンド解釈、又はIDをてがかりにしているコードが
  コントロールを判別できること

だけであり、極論すれば、

 2.1.が満たされるのであればあらゆるIDの重複が許され、実際に
  OSはIDにたよる処理は一切していないし、原理的に不可能

ということになります。
つまり、予約されているものは「やや危険」なだけであり、それを除けば、
その割付は自由にしてかまわないわけですね。

ちなみに、WM_COMMANDは次のような仕組みでコントロールの動作を伝えます。
 LOWORD( WPARAM) : WM_COMMANDを修飾するID
 HIWORD( WPARAM) : 報告コード(何が起こったか=コントロールにより異なる)
 LPARAM     : (発行したものがウインドウならば)発行者のHWND
ウインドウ以外でWM_COMMANDを発行するのはメニューとアクセラレータ
ですが、この場合LPARAMは0「=有効でないHWND」値を設定します。
実際、メニューとツールバーのボタンに同じIDを設定し、処理を共通化するのは
良く見るコードですね。
つまり、HWNDに付随するウインドウIDと、WM_COMMANDのコマンドIDとは
本来的には無関係であるという事実を、この仕様から読み取れるわけです。

さて、上記を勘案すると回答は
>そのダイアログ内でIDが正しく割り振られていれば、
>プロジェクト間で一意になっている必要は無いのかなと思ったのですが。

これは、yesとわかりますよね。

瀬戸っぷ [E-Mail] 2011/09/28(水) 23:12:53
MFCじゃありませんが…

ダイアログのスタイルにDS_CONTEXTHELPを付けていて、
[?]ボタンでのヘルプとして受け取るときに
LPHELPINFO->iCtrlIdでIDで受け取っています。
で、そのIDで文字列リソースを引っ張ってきてHtmlHelp()でポップアップなヘルプを…
とやっているので、各ダイアログのリソースIDは重複なしで設定していたりします。
…まぁ、LoadString()する時のリソースIDの渡し方を工夫すればそんなコトしないで済む
んですけどね。

BOOL ContextHelpDisp(LPHELPINFO lpHelpInfo)
{
    BOOL bResult = FALSE;
    char szHelpText[MAX_PATH];

    if(LoadString(hInst, lpHelpInfo->iCtrlId, szHelpText, MAX_PATH)) {
        HH_POPUP hp;

        ZeroMemory(&hp, sizeof(HH_POPUP));
        hp.cbStruct = sizeof(HH_POPUP);
        hp.pszText = szHelpText;
        hp.clrForeground = static_cast<COLORREF>(-1);
        hp.clrBackground = static_cast<COLORREF>(-1);
        hp.pt.x = lpHelpInfo->MousePos.x;
        hp.pt.y = lpHelpInfo->MousePos.y;
        hp.rcMargins.left = 15;
        hp.rcMargins.right = 15;
        hp.rcMargins.top = 10;
        hp.rcMargins.bottom = 10;
        HtmlHelp(static_cast<HWND>(lpHelpInfo->hItemHandle), NULL,
HH_DISPLAY_TEXT_POPUP, reinterpret_cast<DWORD>(&hp));
        bResult = TRUE;
    }
    return bResult;
}

こんな感じで、各ダイアログからWM_HELPの時に呼んでいたりします。

ということで、そういう妙な使い方しない限りはそれぞれのダイアログでリソースIDがカ
ブっても問題ない…でしょう。

いしだ 2011/10/05(水) 09:42:34
[[解決]]
お二方、ありがとうございます。
MFC拡張DLLとMFCアプリケーション間でリソースIDが被ってはいけないのは、
ダイアログ自身や文字列など、リソースから直接読み込むところのみで、
ダイアログ内のコントロールのIDは被っても問題無いということですね。

古いスレッドには追加発言できません。