rsk82
rsk82

Reputation: 29407

How to determine that FindText dialog is closed when user click "Cancel"

This code produces simple FindText dialog window and when user clicks top-right X window close button the WM_CLOSE message is send to the hook procedure, but when clicking "cancel" button no message is produced to indicate that window ceased to be.

#include <windows.h>
#include <iostream>
#include <iomanip>

UINT_PTR CALLBACK FRHookProc(HWND hdlg, UINT uiMsg, WPARAM /*wParam*/, LPARAM /*lParam*/) {
  switch (uiMsg) {
    case WM_INITDIALOG: {
      ShowWindow(hdlg, SW_SHOW);
      break;
    }
  }
  using namespace std;
  if (uiMsg == WM_CLOSE) cout << "FindTextW window has been closed";
  return 0;
}

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  return DefWindowProcW(hWnd, Msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int /* nCmdShow*/) {
  using namespace std;

  WNDCLASSEXW wc;
  wc.cbSize = sizeof(WNDCLASSEXW);
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = &MyWndProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = sizeof(PVOID);
  wc.hInstance = hInstance;
  wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  wc.hIconSm = NULL;
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BACKGROUND);
  wc.lpszMenuName = L"MainMenu";
  wc.lpszClassName = L"window";
  ATOM class_atom = RegisterClassExW(&wc);

  HWND hWnd = CreateWindowExW(
    0,
    reinterpret_cast<LPCWSTR>(class_atom),
    L"window title",
    WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPCHILDREN | WS_THICKFRAME,
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
    NULL,
    NULL,
    hInstance,
    NULL
  );

  WCHAR szFindWhat[MAX_PATH] = {0};

  FINDREPLACEW fr;
  ZeroMemory(&fr, sizeof(fr));
  fr.lStructSize = sizeof(fr);
  fr.hwndOwner = hWnd;
  fr.lpstrFindWhat = szFindWhat;
  fr.lpfnHook = FRHookProc;
  fr.wFindWhatLen = MAX_PATH;
  fr.Flags = FR_ENABLEHOOK;
  /*HWND hdlg =*/ FindTextW(&fr);

  MSG msg;
  for (;;) {
    GetMessageW(&msg, 0, 0, 0);
    TranslateMessage(&msg);
    DispatchMessageW(&msg);
  }
  return 0;
}

Upvotes: 1

Views: 520

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 598011

Read the documentation more carefully. You took the completely wrong approach to detecting the dialog window being closed.

FindText function:

Before calling FindText, you must call the RegisterWindowMessage function to get the identifier for the FINDMSGSTRING message. The dialog box procedure uses this identifier to send messages when the user clicks the Find Next button, or when the dialog box is closing.

FINDMSGSTRING message:

A Find or Replace dialog box sends the FINDMSGSTRING registered message to the window procedure of its owner window when the user clicks the Find Next, Replace, or Replace All button, or closes the dialog box.

...

You must specify the FINDMSGSTRING constant in a call to the RegisterWindowMessage function to get the identifier for the message sent by the dialog box.

When you create the dialog box, use the hwndOwner member of the FINDREPLACE structure to identify the window to receive FINDMSGSTRING messages.

...

The Flags member of the FINDREPLACE structure includes one of the following flags to indicate the event that caused the message.

FR_DIALOGTERM (0x00000040) The dialog box is closing. After the owner window processes this message, a handle to the dialog box is no longer valid.

So, with that said, try this instead:

#include <windows.h>
#include <iostream>
#include <iomanip>

static const UINT uFindMsgString = RegisterWindowMessageW(L"commdlg_FindReplace");

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  if ((Msg == uFindMsgString) && (Msg != 0))
  {
    FINDREPLACE *fr = reinterpret_cast<FINDREPLACE*>(lParam);
    if (fr->flags & FR_DIALOGTERM)
    {
      std::cout << "FindTextW window has been closed";
      PostQuitMessage(0);
    }

    // process other dialog notifications as needed...

    return 0;
  }

  return DefWindowProcW(hWnd, Msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int /* nCmdShow*/)
{
  WNDCLASSEXW wc = {0};
  wc.cbSize = sizeof(WNDCLASSEXW);
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = &MyWndProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = sizeof(PVOID);
  wc.hInstance = hInstance;
  wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  wc.hIconSm = NULL;
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BACKGROUND);
  wc.lpszMenuName = L"MainMenu";
  wc.lpszClassName = L"window";

  ATOM class_atom = RegisterClassExW(&wc);

  HWND hWnd = CreateWindowExW(
    0,
    wc.lpszClassName,
    L"window title",
    WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPCHILDREN | WS_THICKFRAME,
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
    NULL,
    NULL,
    hInstance,
    NULL
  );

  WCHAR szFindWhat[MAX_PATH] = {0};

  FINDREPLACEW fr = {0};
  fr.lStructSize = sizeof(fr);
  fr.hwndOwner = hWnd;
  fr.lpstrFindWhat = szFindWhat;
  fr.wFindWhatLen = MAX_PATH;

  HWND hdlg = FindTextW(&fr);

  MSG msg;
  while (GetMessageW(&msg, 0, 0, 0) > 0)
  {
    if (!IsDialogMessage(hdlg, &msg))
    {
      TranslateMessage(&msg);
      DispatchMessageW(&msg);
    }
  }

  DestroyWindow(hWnd);
  UnregisterClass(wc.lpszClassName, hInstance);

  return 0;
}

Upvotes: 2

HerrJoebob
HerrJoebob

Reputation: 2313

You should be getting a WM_COMMAND notification for the cancel button's BN_CLICKED message. When 'cancel' is pressed you should get that notification for the IDCANCEL control ID.

Upvotes: 0

Related Questions