Search code examples
c++winapivisual-c++nativewin32gui

How to handle NM_CLICK for Syslink control


Did quite a bit of research trying to figure out how to get this to work properly. I read that if you filter WM_NOTIFY -> NM_CLICK, it would catch the actual click event of the syslink. Trouble is that it catches the event, though it gets stuck in a endless recursion and in a few seconds you have hundreds of browser windows or w/e the link open's up as.

Steps taken:

  1. Create Syslink on dialog
  2. Add title to Syslink control link and change IDD to IDC_LINK1
  3. Filter WM_NOTIFY for NM_CLICK events

       case WM_NOTIFY:
      //case NM_CLICK:
      switch(LOWORD(wParam))
      {
          case NM_CLICK:
             switch(LOWORD(wParam))
         {
                 case IDC_LINK1:
                     // Standard ShellExecute with added check for IsLinkCtrl to make sure its the right kind of control.
                     OpenLink(hWndDlg, LOWORD(wParam));            
             break;
         }
         break;
      }
      break;
    

I guess my real question is how do I do this properly? I don't see any good examples that show how a Syslink is properly filtered to execute a link as a url.


Solution

  • I found a successful way to get this to work without going into recursion. The message loop seems to keep reading in a continuous loop and if you don't filter by using the correct structure it will fall into a infinite recursion. This works for me. If you have better input by all means please do addon.

    The correct steps to take.

    1. Create WM_NOTIFY Message filter event.
    2. Create Switch statement using NMHDR to parse the code for NM_CLICK.
    3. Check wParam to identify correct control being clicked.
    4. Execute link with ShellExecute.

    The following code was used.

           case WM_NOTIFY:
               //NMHDR* pHeader = (NMHDR*)lParam;
               //NMLINK* pNMLink = (NMLINK*)lParam;
               //LITEM iItem = pNMLink->item;
               switch(((NMHDR *)lParam)->code)
               {
                   case NM_CLICK:
                   { // Included to avoid "case" skip statements.
                       times++;
    
                       NMLINK* pNMLink = (NMLINK*)lParam;
                       LITEM iItem = pNMLink->item;
                       // Custom OutputDebugString
                       winapi::Output("NM_CLICK: Fired %d time%s!\n", times, (times <= 1) ? L"" : L"s");
    #ifdef DEBUG
                       assert(iItem.szID);
                       MessageBox(NULL, (LPCWSTR)lParam, L"Assert", MB_OK|MB_ICONINFORMATION);
    #endif
                       if(wParam == IDC_LINK1)
                       {
                           winapi::Output("Success!");
                           OpenLink(hWndDlg, LOWORD(wParam));
                       }
    

    Note:Use NMLINK structure if you rely on your link containing HTML attributes (link or here) to feed Shellexecute its url path.