2013-08-24 11 views
0

업데이트 : 요청한대로 Window 및 RichEdit 컨트롤을 만드는 데 사용하고있는 코드를 모두 추가했습니다.MSFTEDIT_CLASS (RichEdit) 컨트롤에서 Windows 메시지를 올바르게 처리하는 방법?

다른 창 자식으로 사용되는 RichEdit 컨트롤에 대한 Windows 메시지를 처리하려고합니다.

이제 RichEdit 컨트롤이 내 자신의 WndProc을 제외하고 작동하게되었습니다. 문제는 wc.lpszClassName = MSFTEDIT_CLASS;CreateWindowEx()에 사용 된 lpClassName과 일치하도록 설정하면 더 이상 RichEdit 컨트롤의 내용 (예 : 텍스트 등)이 표시되지 않지만 해당 WndProc 함수가 메시지를 처리 ​​할 수 ​​있다는 것입니다.

윈도우의 생성 :

최초 생성자 :

SubWindow::SubWindow(const wchar_t *szAppNameImport) 
{ 
    szAppName = szAppNameImport; 

    cfmt = CHARFORMATW(); 
    hwnd = HWND(); 
    windowRect = RECT(); 
    editControlHwnd = HWND(); 
    wc = WNDCLASSEX(); 

    wc.cbSize = sizeof(WNDCLASSEX); 
    wc.style = CS_CLASSDC; 
    wc.lpfnWndProc = WndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance = GetModuleHandle(NULL); 
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 
    wc.lpszMenuName = NULL; 
    wc.lpszClassName = szAppName; 
    wc.hIconSm = LoadIcon(wc.hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); 
} 

이어서 Create() 기능 :

VOID SubWindow::Create(unsigned int window_startX, unsigned int window_startY, unsigned int windowWidthInput, unsigned int windowHeightInput, HWND parent) 
{ 
    windowRect.left = window_startX; 
    windowRect.top = window_startY; 

    windowRect.right = windowWidthInput; 
    windowRect.bottom = windowHeightInput; 

    if(!RegisterClassEx(&wc)) 
    { 
     throw std::exception(); 
    } 

    if((hwnd = CreateWindowEx 
     (
     WS_EX_CLIENTEDGE, 
     szAppName, 
     TEXT("Our classy sub window!"), 
     WS_OVERLAPPEDWINDOW| WS_VISIBLE, 

     windowRect.left, windowRect.top, 
     windowRect.right, windowRect.bottom, 
     parent, 
     NULL,  
     wc.hInstance, 
     NULL))==NULL) 
    { 
     throw std::exception(); 
    } 

    SetWindowLongPtr(hwnd, GWL_USERDATA, (LONG_PTR)this); 

    ShowWindow(hwnd, SW_SHOWDEFAULT); 
    UpdateWindow(hwnd); 
} 

의 WndProc :

LRESULT CALLBACK SubWindow::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    SubWindow *childWindowPointer = (SubWindow*)GetWindowLongPtr(hwnd, GWLP_USERDATA); 

    if(childWindowPointer != NULL) 
    { 
     if(childWindowPointer->GetEditControl() == hwnd) 
      OutputDebugString(L"I SHOULD NOT BE CALLED"); 

     return childWindowPointer->MsgProc(hwnd, uMsg, wParam, lParam); 
    } 
    else 
    { 
     return DefWindowProc(hwnd, uMsg, wParam, lParam); 
    } 
} 

MsgPr OC :

LRESULT SubWindow::MsgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    PAINTSTRUCT ps; 
    HDC hdc; 

    switch(uMsg) 
    { 
    case WM_WINDOWPOSCHANGED: 
     { 
      GetClientRect(hwnd, &windowRect); 
      SetWindowPos(editControlHwnd, NULL, windowRect.left, windowRect.top, windowRect.right, windowRect.bottom, SWP_NOZORDER | SWP_NOACTIVATE); 
      return 0; 
     } 
    case WM_DESTROY: 
     { 
      OutputDebugString(TEXT("DESTROYING A SUB WINDOW!\n")); 
      return 0; 
     } 

    case WM_PAINT: 
     { 
      InvalidateRect (hwnd, NULL, FALSE); 
      hdc = BeginPaint(hwnd, &ps); 
      EndPaint(hwnd, &ps); 
      return 0; 
     } 

    case EM_EXSETSEL: 
     { 
      if(hwnd == editControlHwnd) 
      { 
       OutputDebugString(L"Text selection changed"); 
       return 0; 
      } 
     } 
    } 
    return DefWindowProc(hwnd, uMsg, wParam, lParam); 
} 

RichEdit 컨트롤은 내가 정의한 WndProc를 사용하지 않고, 분명히 문제없이, 무 완벽하게 작동합니다.

내가 잘못하고있는 것이 무엇인지, 올바르게 해결할 수 있는지 잘 모르겠습니다. 편집

: 답변과 의견을 바탕으로 , 나는 RichEdit 컨트롤을 포함 만 Window 클래스를 사용하려면 코드를 복원 한 thusly 히 만든 :

void SubWindow::CreateEditControl() 
{ 
    std::wstring initialText = TEXT("TestWindow\r\n"); 

    LoadLibrary(L"Msftedit.dll"); 

    GetClientRect(hwnd, &windowRect); 
    editControlHwnd = CreateWindowEx(0, MSFTEDIT_CLASS, initialText.data(), 
     WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_READONLY | WS_VSCROLL | ES_NOHIDESEL, 
     windowRect.left, windowRect.top,windowRect.right,windowRect.bottom, 
     hwnd, 
     NULL, NULL, NULL); 

    cfmt.cbSize = sizeof(CHARFORMAT); 
    cfmt.dwMask = CFM_COLOR | CFM_FACE | CFM_SIZE; 
    cfmt.dwEffects = 0; 
    cfmt.yHeight = 160; 
    cfmt.crTextColor = RGB(0,0,0); 
    wcscpy_s(cfmt.szFaceName, TEXT("Tahoma")); 

    SendMessage(editControlHwnd, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cfmt); 
} 

가 어떻게에서 메시지를 처리 ​​할 창 MsgProc 에서이 컨트롤?

+1

'MSFTEDIT_CLASS'라는 이름으로 자신의 클래스를 등록하면 효과적으로 원본을 대체합니다. 이 작업을 완료하면 원래 클래스에 더 이상 액세스 할 수 없으며 대신 'MSFTEDIT_CLASS'를 만들면 클래스가 생성됩니다. 이것은 한 파일을 다른 파일로 덮어 쓰는 것과 같습니다. 목표가 무엇인지는 분명하지 않습니다. 리치 에디트 컨트롤을 부분적으로 대체하고 싶습니까? 하나의 창만 들어 봤어? 아니면 단순히 창문에서 메시지 *에 응답하려고합니까? –

+0

하나 이상의 윈도우에서 하나의 RichEdit 컨트롤을 만들려고했지만, 지금은 하나뿐입니다. – Interminable

+0

그런 다음 표준 'MSFTEDIT_CLASS'를 만듭니다. 나 자신을 쓰려고하지 마라. 말했듯이 표준 컨트롤을 사용하면 "RichEdit 컨트롤이 완벽하게 작동하고 완벽하게 작동합니다." –

답변

1

기본 클래스 이름 (MSFTEDIT_CLASS)을 사용하여 리치 편집 컨트롤 창을 만들면 모든 메시지가 상위 창으로 전송됩니다. 부모 창은 아니기 때문에 이러한 메시지를 처리 ​​할 수 ​​없습니다.

따라서 메시지를 부모에게 전달하는 대신 자신의 윈도우 프로 시저를 직접 호출하여 컨트롤을 서브 클래스 화해야합니다.그것은 간단합니다. 전에 this answer for a regular edit control에서 논의했습니다.

// Stores the old original window procedure for the rich edit control. 
WNDPROC wpOldRichEditProc; 

// The new custom window procedure for the rich edit control. 
LRESULT CALLBACK CustomRichEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    switch (msg) 
    { 
     ... 
    } 

    // Pass the messages you don't process on to the original window procedure. 
    CallWindowProc(wpOldRichEditProc, hWnd, msg, wParam, lParam); 
} 

을 그리고 당신은 컨트롤 만들 때 : 변경된 예제 코드는 다음과 같습니다

// Create the rich edit control 
HWND hWnd = CreateWindowEx(...) 

// Subclass it. 
wpOldRichEditProc= (WNDPROC)SetWindowLongPtr(hWnd, 
              GWLP_WNDPROC, 
              (WNDPROC)CustomRichEditProc); 

을 또한가 파괴 될 때마다 제어 unsubclass 에 있는지 확인해야합니다. 다른 예는 부모 창에 의해 수신 된 메시지에 대한 응답으로이를 수행하는 것을 보여 주지만, 부모 창에 대한 메시지를받지 못하기 때문에 사용자의 경우에는 작동하지 않습니다. 대신, 자신의 WM_NCDESTROY 메시지에 대한 응답으로 컨트롤에서 서브 클래스를 제거해야합니다 : 공용 컨트롤 라이브러리의

SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)wpOldRichEditProc); 

또는 버전 6은 a set of utility functions를 사용하여 하위 클래스의 새로운 덜 오류가 발생하기 쉬운 방법을 소개 . (중요한 기능은 실제로 이전 버전에 있었지만 문서화되지 않았습니다.) 실제로 창을 소유하고있는 프로세스를 제어 할 수 없다는 점을 감안할 때 이것은 바람직한 접근 방법 일 것입니다.

두 가지 방법 모두 데모가 있습니다. here on MSDN.

물론 개별 컨트롤 만 하위 클래스 할 필요는 없습니다. 또한 내장 된 rich edit 컨트롤과 같은 방식으로 작동하는 사용자 정의 윈도우 클래스를 등록 할 수 있지만 해당 클래스의 윈도우에서 수신 한 메시지에서 처음 균열이 발생합니다. 그 것이 필요한 것인지 아닌지에 대해서는 말할 수 없습니다. 그것 소리처럼 당신은 당신이 걱정하는 하나의 컨트롤을 가지고.

+0

'원래'문제는 부모 창에서 RichEdit 컨트롤의 메시지를 가져 오지 못했기 때문에 RichEdit 컨트롤을 해당 컨트롤로 옮긴 이유입니다. 자신의 수업. – Interminable

+0

@Interminable 어떻게 그 일을했는지 ​​보지 못했습니다. 질문의 맨 위에 'wc.lpszClassName'에 대해 혼란스러운 점이 있지만 그와 함께 진행되는 코드가 없으므로 그 내용이 무엇인지 모릅니다. 어쨌든, 문제는 당신이 rich edit control을위한 기본 윈도우 프로 시저를 호출하지 않는다는 것입니다. 즉, 잘못 서브 클래 싱했다는 의미입니다. –

+0

두 개의 wc 구조체가 각 클래스에 하나씩 있습니다. 하나는'Window' 클래스에 있고, 하나는'EditControl' 클래스에 있습니다. 이전에 섰던 것처럼'EditControl' 클래스도 없었습니다. 대신 단순히'Window' 클래스에'CreateEditControl()'함수를 가지고있었습니다. 그리고'Window' 클래스에는 하나의 wc 구조 만 있습니다. 원한다면 완전히 분리 된'EditControl' 클래스를 만들기 전에 원래 사용했던 코드로 내 질문을 편집 할 수 있습니다. – Interminable

0

wc 구조와 관련된 코드를 표시 할 수 있습니까? 메인 윈도우가 리치 에디트 컨트롤과 같은 클래스를 가지기를 원하지 않는다고 확신합니다 - 그리고 그것은 제가 지금까지 읽었던 것입니다.

풍부한 편집 컨트롤에 WNDCLASSEX이 적용되는 이유를 모르겠습니다.

제 제안은 당신이 EditControl::WndProcGWL_WNDPROC과 함께 SetWindowLong()을 사용하여 풍부한 편집 컨트롤을 만든 후이를 단순화하고 서브 클래 싱한다는 것입니다.

+0

내 게시물에 이제 창과 RichEdit 컨트롤을 만드는 데 사용하는 모든 코드가 포함되어 있습니다. – Interminable

1

원래 문제는 상위 창이 RichEdit 컨트롤에서 알림 메시지를받지 못했다는 것입니다. RichEdit 컨트롤에 EM_SETEVENTMASK 메시지를 보냈습니까? 그렇지 않으면 RichEdit 컨트롤이 부모 창에 특정 알림 메시지를 보내지 않습니다. EM_SETEVENTMASK message을 참조하십시오.