Question

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.

Was it helpful?

Solution 2

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.

OTHER TIPS

Just to clarify, I do not think you are using managed C++, there for I am not sure why you are referring to a NM_CLICK notificaton code as an event. Besides, you do not have to catch anything, you are not handling any exceptions, you are just handling a WM_NOTIFY message.

Anyway, I am not sure why you experience this particular behavior since I do not see what you do outside of the code snippet but I know what is causing it. In our code snippet you use wParam to determine a notification code and this is incorrect. This control does not use wParam. To determine notification code you should do the following:

    NMHDR* pHeader = (NMHDR*)lParam;

    switch (pHeader->code)

pHeader->code holds the notification code value you should use and pHeader->hwndFrom is the handle of the control that was clicked.

Furthermore, you using LOWORD(wParam) again and pass it as the parameter to function call. You are not showing what you do in this function but I can conclude that the code is also not correct. The same lParam is a pointer to the NMLINK structure. First member of this structure is mentioned above NMHDR, the next member is LITEM structure that should be used to determine what the URL is.

    NMLINK* pNMLink = (NMLINK*)lParam;
    LITEM iItem = pNMLink->item;

item.szUrl is the URL you should use in call to ShellExecute call open.

Either

  1. your OpenLink function results in another message being sent (most likely), or

  2. This isn't the only code where OpenLink is called, or

  3. you reach this code not from WM_NOTIFY, but from fall-through of the case above, or

  4. you call DefWindowProc for the message, even though you already handled it.

Try

  break; // make sure there's no fall-through here
  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));            
             return TRUE; // handled, don't pass to DefWindowProc
     }
     break;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top