2

I am using the current code to highlight URLs on a TRichEdit:

procedure TForm1.WndProc(var Message: TMessage);
var
  p: TENLink;
  strURL: string;
begin
  if (Message.Msg = WM_NOTIFY) then
  begin
    if (PNMHDR(Message.lParam).code = EN_LINK) then
    begin
      p := TENLink(Pointer(TWMNotify(Message).NMHdr)^);
      if (p.Msg = WM_LBUTTONDOWN) then
      begin
        SendMessage(RichEdit1.Handle, EM_EXSETSEL, 0, Longint(@(p.chrg)));
        strURL := RichEdit1.SelText;
        ShellExecute(Handle, 'open', PChar(strURL), 0, 0, SW_SHOWNORMAL);
      end
    end;
  end;

  inherited;
end;

procedure TForm1.InitRichEditURLDetection;
var
      mask: Word;
begin
      mask := SendMessage(Handle, EM_GETEVENTMASK, 0, 0);
      SendMessage(RichEdit1.Handle, EM_SETEVENTMASK, 0, mask or ENM_LINK);
      SendMessage(RichEdit1.Handle, EM_AUTOURLDETECT, Integer(True), 0);
      form1.RichEdit1.OnChange := form1.RichEdit1Change;
end;

It highlights the URLs, however it prevent my RichEdit1.OnChange from being called. I trying setting again from within WndProc and other approaches but nothing works. The minute I enable the URL highlighter (by calling InitRichEditURLDetection on FormCreate) OnChange stops working.

This is on Delphi 7.

Any suggestions? thanks!

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
Jessica
  • 2,005
  • 4
  • 28
  • 44

1 Answers1

2

There is a bug in your code. Replace

mask := SendMessage(Handle, EM_GETEVENTMASK, 0, 0);

with

mask := SendMessage(RichEdit1.Handle, EM_GETEVENTMASK, 0, 0);

Because of this bug, mask will not contain the default event bits of the Rich Edit control, so the Rich Edit control looses these event flags when you EM_SETEVENTMASK; in particular, it will lack the ENM_CHANGE bit.

Update

Sertac Akyuz found yet another show-stopping bug: mask needs to be an integer (which indeed is the result type of SendMessage).

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • thanks, I tried it. I get a eRangeError exception on that line when I try to run it – Jessica Aug 24 '10 at 18:18
  • @Jessica: Are you sure? (Maybe a stupid question, but it really should work.) – Andreas Rejbrand Aug 24 '10 at 18:20
  • I tried also with: http://stackoverflow.com/questions/2480173/detect-click-on-url-in-richedit but I get a different exception. – Jessica Aug 24 '10 at 18:23
  • @Jessica: Create a new, empty, VCL application. Drop a `TRichEdit` on the form. Call `InitRichEditURLDetection` on `FormCreate` (with my correction, but without the `OnChange := ` part). Override the form's `WndProc` using your original code (which is fine). Set `RichEdit1.OnChange` to something silly like `Caption := IntToStr(length(RichEdit1.Text));` Does it work now? – Andreas Rejbrand Aug 24 '10 at 18:26
  • yes, but it doesn't allow me to click on the URL. Nothing happends – Jessica Aug 24 '10 at 18:34
  • if I add any other component or if I do point the OnChange to any other procedure then it throws an exception on the line you corrected. Try with Richedit1.OnChange := form1.RichEdit1Change; where RichEdit1Change has Caption := IntToStr(length(RichEdit1.Text)); – Jessica Aug 24 '10 at 18:38
  • @Jessica: OK. I have created a minimal test project (a *.pas, a *.dfm, a *.dpr, and a compiled *.exe) here: http://privat.rejbrand.se/RichEditURLs.zip. Try to open this project, and see if it works (by doing so we'll find out if that there are any other bugs in your code, hidden somewhere). If you dare, you can even try the compiled *.exe. If it still doesn't work (not even the compiled *.exe), then I'll promise that I'll start believing you! – Andreas Rejbrand Aug 24 '10 at 18:44
  • I wish I could post a screenshot. It gives me an exception as well. On the same line. Could this be related only to delphi 7 or windows 7? – Jessica Aug 24 '10 at 18:51
  • OK. I run Windows 7, so there is not an issue with the operating system (which generally is very free from bugs). Most likely there is a bug in the implementation of the Rich Edit wrapper in Delphi 7 (or it is an older version of the Rich Edit control). Since I do not have Delphi 7 available, I am afraid that I cannot help you. Sorry. (I assume that the compiled *.exe did work if you tried it?) Nevertheless, the bugthat I pointed out in your original code is very real, so without my correction, it will not work with any Delphi/Windows version! – Andreas Rejbrand Aug 24 '10 at 18:53
  • I didn't try the compiled exe. Sorry, as much as I trust you on a good answer I don't trust anyone's exe but those I can compile. – Jessica Aug 24 '10 at 18:54
  • ok. I'll accept this answer since you are sure it works... however I am still getting the exception. thanks for the help, i really appreciate it – Jessica Aug 24 '10 at 18:55
  • Well, even if I am unable to help you, someone with Delphi 7 might be able to. I will add the tag "Delphi-7" to your question, so that it gets some more attention from other users. – Andreas Rejbrand Aug 24 '10 at 19:08
  • 2
    @Jessica - `SendMessage` returns a `LRESULT`. You should declare `mask` as such, or a `Longint`. – Sertac Akyuz Aug 24 '10 at 19:30
  • 1
    @Jessica: Indeed, Sertac has found a second show-stopping bug! `ENM_LINK = 67108864` cannot be stored in a 16-bit word; we need all 32 bits. This explains why you do not get the proper behaviour, but rather "random bugs". For some reason (luck), the bug did not cause any problems on my system. I should have seen it earlier, but better now than never. If you fix my bug **and** Sertac's bug, then it will probably work! (Btw: a `LRESULT`, or a `LongInt`, is simply a normal `integer`, 32-bit and signed.) – Andreas Rejbrand Aug 24 '10 at 19:37
  • As a sidenote, I suppose you originally got the code from http://www.scalabium.com/faq/dct0146.htm. Someone should inform them about these bugs. – Andreas Rejbrand Aug 24 '10 at 19:39
  • 1
    While shaving, I figured out why I did not detect this latter bug. Indeed, we `or ENM_LINK` directly in the call to `SendMessage`, so the high "link" bit need not be saved in `mask`. The effect of this bug, thus, is limited to the nullification of all *other* default bits > 16. In light of this, I find it slightly hard to believe that this is what is causing Jessica's issues, but since it probably is the only bug not yet corrected, I suspect that everything will work for her when this bug is fixed as well. – Andreas Rejbrand Aug 24 '10 at 19:54
  • @Andreas - It would also cause the 'eRangeError' Jessica mentions, if range checking is enabled that is.. But then she should be getting the error all the way from the beginning. Who knows?.. – Sertac Akyuz Aug 24 '10 at 20:02
  • @Marjan - Yet one wonders if Jessica's code will work.. I know one sometimes wishes if one could see one's desktop.. :) – Sertac Akyuz Aug 24 '10 at 21:02
  • Thanks everyone for the tips. I tried setting mask as LRESULT and indeed it stops the exception from happening. however I get now random exceptions when I click on the highlighted URL, even to the point to freezing the app completely. – Jessica Aug 27 '10 at 13:02