0

何が原因ShowCaretSetCaretPos失敗する可能性がありERROR_ACCESS_DENIEDますか?

でキャレットを作成し、でキャレットWM_CREATEを表示していますWM_COMMAND。確認したところ、CreateCaret正常に実行されています。

それらは同じスレッドで実行されている必要があります。

呼び出す前にSetScrollInfoandを使用して、ウィンドウのコンテンツを更新します。しかし、私はこれらが失敗する原因になるとは思わない..InvalidateRectShowCaretShowCaret

関連コード:

#define CHAR_WIDTH  7
#define CHAR_HEIGHT 12

case WM_CREATE:
    CreateCaret(hWnd, NULL, CHAR_WIDTH, 2);
    UpdateScrollbar(hWnd); // calls SetScrollInfo. initially nMin and nMax are both 0
    return 0;

case WM_COMMAND:
    switch(LOWORD(wParam))
    {
    case IDM_OPENFILE:
        if (DoOpenFile(hWnd))
        {
            InvalidateRect(hWnd, NULL, TRUE);
            UpdateScrollbar(hWnd);

            if (SetCaretPos(CHAR_WIDTH * 12, CHAR_HEIGHT - 1) == 0)
            {
                char ss[33];
                sprintf_s(ss, "DEBUG 2: %d\n", GetLastError());
                OutputDebugString(ss);
            }

            if (ShowCaret(hWnd) == 0)
            {
                char ss[33];
                sprintf_s(ss, "DEBUG 3: %d\n", GetLastError());
                OutputDebugString(ss);
            }
        }
        break;
    }
    return 0;
4

1 に答える 1

5

はい、これを正しく行っていません。メッセージ キューごとに (つまり、スレッドごとに) キャレットは 1 つだけです。別のウィンドウが既にキャレットを持っている場合、キャレットを作成することはできません。最も可能性が高いのは編集ボックスです。ウィンドウがフォーカス、WM_SETFOCUS メッセージを受け取るまでは、キャレットを作成したり、表示したりしてはなりません。また、ウィンドウがフォーカスを失ったときに破棄する必要があります。WM_KILLFOCUS メッセージです。

GetLastError() の使用方法も危険ですが、おそらくすぐに回避できます。C または C++ で引数が評価される順序は決定論的ではありません。引数式の 1 つがエラー コードを変更するリスクがあります。何かを呼び出す前に常にエラー コードを取得し、それをローカル変数に格納します。

また、エラー チェックをスキップしないでください。少なくとも、戻り値を assert() する必要があります。作成されたばかりのウィンドウにはフォーカスがないため、CreateCaret() 呼び出しは現在失敗している可能性があります。

于 2013-03-02T16:26:45.523 に答える