views:

438

answers:

4

Most TWinControl descendant in Delphi has an override method CreateParams to define it's subclass such as: 'EDIT', 'COMBOBOX', 'BUTTON', 'RICHEDIT' and etc.

CreateSubClass(Params, 'EDIT');
CreateSubClass(Params, 'COMBOBOX');
CreateSubClass(Params, 'BUTTON');

There are quite a number of rich edit control for Delphi including controls from third party vendors. All those controls are sub class of RichEdit.

I am wondering if there is a way to test a control is RichEdit regardless of it's original vendor by testing the SubClass defined in CreateParams?

A: 

Am I missing something? Is it not simply a case of testing:

if (MyControl is TRichEdit)

or

if (MyControl is TCustomRichEdit)
_J_
These are the Delphi's VCL rich edit controls. There are TcxRichEdit, TRxRichEdit, and more...
Chau Chee Yang
That only works for controls that derive from T(Custom)RichEdit. It will not work for controls that derive from TWinControl or TCustomControl instead.
Remy Lebeau - TeamB
Yes but in your question you said, "There are quite a number of rich edit control for Delphi including controls from third party vendors. All those controls are sub class of RichEdit." If they're a subclass of TRichEdit then the `is` test works.
_J_
@_J_: No, it doesn't, subclassing in this context has nothing to do with Delphi's inheritance.
TOndrej
cxControls inherit from TcxControl which in turn comes from TCustomControl so this wont work for those.
JamesB
The "sub class" is not meant for Delphi class inheritance. It is CreateSubClass invoke in method CreateParams.
Chau Chee Yang
OK thanks guys, looks like I *was* missing something. :o)
_J_
+1  A: 

Use the Win32 API GetWindowClass() function and then check for the various rich edit class versions that are available - 'RICHEDIT' (1.0), 'RICHEDIT20A' or 'RICHEDIT20W' (2.x+), and 'RICHEDIT50W' (4.1).

Remy Lebeau - TeamB
I can't find GetWindowClass in Windows.pas. I am using Delphi 2010.
Chau Chee Yang
I think this would work assuming you could get access to the "ControlClassName" passed through to CreateSubClass.
JamesB
So how would I get access to it? I can't find GetWindowClass in unit windows.pas
Chau Chee Yang
It's GetClassName.
TOndrej
I try GetClassName but it returns the Delphi class name of the control. For example, it returns "TRichEdit" for TRichEdit control instead of 'RICHEDIT', 'RICHEDIT20A' OR 'RICHEDIT20W' mentioned by Remy Lebeau.
Chau Chee Yang
the API name is GetClassName defined in Windows.pas, not GetWindowClass.
vcldeveloper
GetClassName return the VCL's class name, not the window subclass name.
Chau Chee Yang
I'm not sure but maybe you can use RealGetWindowClass (in user32.dll) instead of GetWindowClass
SimaWB
I have tried RealGetWindowClass and it seems return same result as GetWindowClass.
Chau Chee Yang
A: 

You could use

 function GetClassInfo(hInstance: HINST; lpClassName: PChar;  var lpWndClass: TWndClass): BOOL;

I think this is what Remy was trying to do.

something like:

Function IsRichEdit(MyControl : TWinControl):Boolean;
var 
    Info : TWNDClass;
begin
    Result := False;
    if GetClassInfo(HInstance,PCHAR('RICHEDIT'),Info) and (Info.lpfnWndProc = MyControl.DefWndProc) then 
        Result := True
    else if GetClassInfo(HInstance,PCHAR('RICHEDIT20A'),Info) and (Info.lpfnWndProc = MyControl.DefWndProc)  then 
        Result := True
    else if GetClassInfo(HInstance,PCHAR('RICHEDIT30A'),Info) and (Info.lpfnWndProc = MyControl.DefWndProc)  then 
        Result := True
    else if GetClassInfo(HInstance,PCHAR('RICHEDIT41A'),Info) and (Info.lpfnWndProc = MyControl.DefWndProc)  then 
        Result := True
    else if GetClassInfo(HInstance,PCHAR('RICHEDIT50A'),Info) and (Info.lpfnWndProc = MyControl.DefWndProc)  then 
        Result := True
end;

If you are using Delphi > 2007 then you might need to test for the 'W'(unicode) versions as well e.g 'RICHEDIT20W'

Edit: added Info.WndProc test to match the control.

Oddly enough this won't work for the cxControls since the cxRichEdit isn't the control using the rich edit window (It's a containing so you would need to pass cxControl.InnerControl for this to return true).

Edit I couldn't get this to work for more than the first richedit control created.

JamesB
Almost. Except your function will return True for *any* control you pass to it, as long as your application has created a subclass for one of those classes.The first parameter to GetClassInfo is supposed to be application instance (HInstance, or 0 for system classes), not the control's handle.The correct test would probably be:if GetClassInfo(HInstance, 'RICHEDIT', Info) and (Info.lpfnWndProc = THackWinControl(MyControl).DefWndProc) then ...
TOndrej
Your code works. Is this the only way to test if a control a rich edit? There seems to have few RichEdit window class (e.g: RICHEDIT, RICHEDIT20A, RICHEDIT20W, ...). Do you know how many of them? Is there anyway to return the window class name of TWinControl instance? Then I can check if window class name contain 'RICHEDIT'.
Chau Chee Yang
A: 

Thanks for all the feedback. I think there is no way to get the windows class name for the TWinControl.

Here is another version of IsRichEdit modified from JamesB's version:

type TWinControlAccess = class(TWinControl);

function IsRichEdit(C: TWinControl): boolean;

const A: array[0..8] of string = (
           'RICHEDIT',
           'RICHEDIT20A', 'RICHEDIT20W',
           'RICHEDIT30A', 'RICHEDIT30W',
           'RICHEDIT41A', 'RICHEDIT41W',
           'RICHEDIT50A', 'RICHEDIT50W'
          );

var Info: TWNDClass;
    p: pointer;
    s: string;
begin
  p := TWinControlAccess(C).DefWndProc;

  Result := False;

  for s in A do begin
    if GetClassInfo(HInstance, PChar(s), Info) and (Info.lpfnWndProc = p) then begin
      Result := True;
      Break;
    end;
  end;
end;

We may modify array A if there is newer version of RichEdit class from Windows.

Another possible but risky solution is I just check if the control's VCL class name contain 'RichEdit' string as almost rich edit VCL class from Delphi or 3rd party vendors name the controls that way.

Chau Chee Yang