Recent

Author Topic: Change the class name of TForm on win32 ?  (Read 19907 times)

marunguy

  • New Member
  • *
  • Posts: 17
Change the class name of TForm on win32 ?
« on: February 03, 2012, 05:53:06 am »
I am a beginner for lazarus and delphi.
I use Lazarus-0.9.31-35081-fpc-2.6.1-20120202-win32.exe.

I want to change the class name of TForm on win32.

I reference below link.
http://www.delphidabbler.com/articles?article=13&part=2

Code: [Select]
type
  { TFormMain }
  TFormMain = class(TForm)
    ....
  protected
    PrevWndProc: Windows.WNDPROC;
    procedure WndProc( var TheMessage: TLMessage); override;
    procedure CreateParams(var Params: TCreateParams); override;
  end;

procedure TFormMain.CreateParams(var Params: TCreateParams);
begin
  inherited;
  StrCopy(Params.WinClassName, 'MyClass');
end;

procedure TFormMain.MenuItem2Click(Sender: TObject);
var
  class_name :array [0..255] of Char;
  ret :LongInt;
begin
  ret := GetClassName(WindowHandle, class_name, SizeOf(class_name));
  if ret > 0 then
  begin
    MessageDlg(class_name, mtInformation, [mbOK], 0 )
  end;
end;

But, this code don't work on Lazarus.
The class name of TForm don't changed,
class name is 'Window' always.

Class name may be fixed at TWin32WSCustomForm.CreateHandle function in lazarus\lcl\interfaces\win32\win32wsforms.pp.

Code: [Select]
class function TWin32WSCustomForm.CreateHandle(const AWinControl: TWinControl;
  const AParams: TCreateParams): HWND;
var
  Params: TCreateWindowExParams;
  lForm: TCustomForm absolute AWinControl;
  Bounds: TRect;
  SystemMenu: HMenu;
begin
    .......
    CalcFormWindowFlags(lForm, Flags, FlagsEx);
    pClassName := @ClsName[0];  //<- ClsName = 'window'
    WindowTitle := StrCaption;
    ....

How can I change th class name of TForm in Lazarus ?

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3541
Re: Change the class name of TForm on win32 ?
« Reply #1 on: February 03, 2012, 08:00:24 am »
Why do you want to do this?

marunguy

  • New Member
  • *
  • Posts: 17
Re: Change the class name of TForm on win32 ?
« Reply #2 on: February 03, 2012, 10:59:00 am »
FindWindow win32 api is much used to find process and to send message in my C/C++ apps.
It is difficult to change the class name of my C/C++ apps because this name is used in many apps.

I want to port old C/C++ apps to Lazarus.
So, I try to change the class name of TForm instance.

How can I change the class name of TForm instance?

Leledumbo

  • Hero Member
  • *****
  • Posts: 8108
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Change the class name of TForm on win32 ?
« Reply #3 on: February 03, 2012, 12:52:29 pm »
Indeed, it's hardcoded in lazarus\lcl\interfaces\win32\win32int.pp:
Code: Pascal  [Select]
  1. const
  2.   BOOL_RESULT: array[Boolean] of String = ('False', 'True');
  3.   ClsName: array[0..6] of char = 'Window'#0;
  4.   ClsHintName: array[0..10] of char = 'HintWindow'#0;
  5.   EditClsName: array[0..4] of char = 'Edit'#0;
  6.   ButtonClsName: array[0..6] of char = 'Button'#0;
  7.   ComboboxClsName: array[0..8] of char = 'ComboBox'#0;
  8.   ListboxClsName: array[0..8] of char = 'LISTBOX'#0;
  9.   TabControlClsName: array[0..15] of char = 'SysTabControl32'#0;
  10.   ListViewClsName: array[0..13] of char = 'SysListView32'#0;

marunguy

  • New Member
  • *
  • Posts: 17
Re: Change the class name of TForm on win32 ?
« Reply #4 on: February 03, 2012, 01:29:11 pm »
The class name of TForm is fixed in "Window".

Is it possible to changing class name of TForm instance without changing of TForm source?

After call inherited CreateParams at TFormMain.CreateParams procedure,
WinClassName member of  TCreateParams have empty null string.

WinClassName member of  TCreateParams is not used at TWin32WSCustomForm.CreateHandle() function.

Also, PrepareCreateWindow function don't use
WinClassName member of  TCreateParams.

Why exist WinClassName member of  TCreateParams ?

When create TForm instance, does LCL not support change the class name of TForm Instance ?

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3541
Re: Change the class name of TForm on win32 ?
« Reply #5 on: February 08, 2012, 12:08:06 pm »
You can always propose a patch to implement the behavior which you desire, it looks something easy to do.

marunguy

  • New Member
  • *
  • Posts: 17
Re: Change the class name of TForm on win32 ?
« Reply #6 on: February 09, 2012, 10:49:41 am »
I try to change the class name of TForm instance on win32.
The simple way is to change the ClsName variable in lazarus\lcl\interfaces\win32\win32int.pp.
But, I want to change the class name of TFormMine instance.

Below is modified code of lazarus/lcl/interfaces/win32/win32wsforms.pp.
Lazarus-0.9.31-35255-fpc-2.6.1-20120209-win32.exe is used.
As, I am a begginer for lazarus and pascal, it doesn't looks graceful.
Also, I attach the patch file.

Alhough it works for me and tested on Win7, XP.
if  Ansi mode (WindowsUnicodeSupport not defined or UnicodeEnabledOS False ) build, it crashed.
What is wrong?
Who help me?

Code: [Select]
unit Win32WSForms;

{$mode objfpc}{$H+}
{$I win32defines.inc} // added

interface

Code: [Select]
class function TWin32WSCustomForm.CreateHandle(const AWinControl: TWinControl;
  const AParams: TCreateParams): HWND;
var
  Params: TCreateWindowExParams;
  lForm: TCustomForm absolute AWinControl;
  Bounds: TRect;
  SystemMenu: HMenu;
  // addtion start
  WindowClass: WndClass;
{$ifdef WindowsUnicodeSupport}
  WindowClassW: WndClassW;
{$endif}
  AErrorCode: Cardinal;
  // addtion end
begin
  // general initialization of Params
  PrepareCreateWindow(AWinControl, AParams, Params);
  // customization of Params
  with Params do
  begin
    if (Parent = 0) then
    begin
       ......
    end;
    CalcFormWindowFlags(lForm, Flags, FlagsEx);
    pClassName := @ClsName[0];

    // addtion start
    if AParams.WinClassName[0] <> #0 then
    begin
      pClassName := @AParams.WinClassName[0];
    {$ifdef WindowsUnicodeSupport}
      if UnicodeEnabledOS then
      begin
        if not GetClassInfoW(System.HInstance(), PWideChar(WideString(pClassName)), @WindowClassW) then
        begin
          if GetClassInfoW(System.HInstance(), PWideChar(WideString(ClsName)), @WindowClassW) then
          begin
    WindowClassW.lpszClassName:=PWideChar(WideString(pClassName));
    if Windows.RegisterClassW(@WindowClassW) = 0 then
    begin
      AErrorCode := GetLastError;
      //DebugLn(['Failed to RegisterClassW, error: ', AErrorCode, ' : ', GetLastErrorText(AErrorCode)]);
      raise Exception.Create('Failed to RegisterClassW, error: ' + IntToStr(AErrorCode) + ' : ' + GetLastErrorText(AErrorCode));
    end;
          end
          else
          begin
            AErrorCode := GetLastError;
    //DebugLn(['Failed to GetClassInfoW, error: ', AErrorCode, ' : ', GetLastErrorText(AErrorCode)]);
    raise Exception.Create('Failed to GetClassInfoW, error: ' + IntToStr(AErrorCode) + ' : ' + GetLastErrorText(AErrorCode));
          end;
        end;
      end
      else
    {$endif}
      begin
        FillChar(WindowClass, SizeOf(WindowClass),0);
        if not GetClassInfo(System.HInstance(), pClassName, @WindowClass) then
        begin
          if GetClassInfo(System.HInstance(), PChar(AnsiString(ClsName)), @WindowClass) then
          begin
    WindowClass.lpszClassName:=pClassName;
    if Windows.RegisterClass(@WindowClass) = 0 then
    begin
      AErrorCode := GetLastError;
      //DebugLn(['Failed to RegisterClass, error: ', AErrorCode, ' : ', GetLastErrorText(AErrorCode)]);
      raise Exception.Create('Failed to RegisterClass, error: ' + IntToStr(AErrorCode) + ' : ' + GetLastErrorText(AErrorCode));
    end;
          end
          else
          begin
            AErrorCode := GetLastError;
    //DebugLn(['Failed to GetClassInfo, error: ', AErrorCode, ' : ', GetLastErrorText(AErrorCode)]);
    raise Exception.Create('Failed to GetClassInfo, error: ' + IntToStr(AErrorCode) + ' : ' + GetLastErrorText(AErrorCode));
          end;
        end;
      end;
    end;
    // addtion end

    WindowTitle := StrCaption;
    AdjustFormBounds(lForm, Bounds);
    if (lForm.Position in [poDefault, poDefaultPosOnly]) and not (csDesigning in lForm.ComponentState) then
    begin
« Last Edit: February 09, 2012, 10:58:05 am by marunguy »

CCRDude

  • Sr. Member
  • ****
  • Posts: 492
Re: Change the class name of TForm on win32 ?
« Reply #7 on: August 26, 2015, 03:03:29 pm »
I came to this point as well now.

I'm implementing UI testing for an application written in Lazarus.

Locating controls from outside (testing framework) could either depend on captions, or class names. Captions are a bad choice (localizations would need separate tests, changes in text would break tests).

Delphi sets the Pascal class name as the window class name, which allows very specific and safe UI tests. It would be great if the LCL could be adjusted to do the same, since supporting UI testing means supporting good code ;)

I've read through the post above and can confirm that CreateParams does not work (and would need to implement that for every class anyway). I spent an hour digging through Win32WSControls (FinishCreateWindow looks like the place to look at) and Win32WSForms, but the last time I worked with RegisterClass and CreateWindowEx is years ago for Windows CE; and I'm probably missing something, since while I could add code to register a custom window class, there must be something tied to a later point in the code, since it would fail anyway; plus, I could only get e.g. TWin32WSCustomForm as AWinControl.ClassName, not the name of my form which probably is based on that (TMyAppMainForm).

CCRDude

  • Sr. Member
  • ****
  • Posts: 492
Re: Change the class name of TForm on win32 ?
« Reply #8 on: September 08, 2015, 08:07:15 am »
After AutoIt failed for me because of this, I now made a test run with TestComplete, because they said it should work the same way as Delphi. Well, I guess they handle class names for Delphi apps as well, and don't support any Lazarus debug info, because it was the same issue: generic class names and buttons and controls only identified by position on the UI or labels even don't make up for good UI tests that are stable across minor UI changes or localization changes.

The first real disadvantage I've seen in Lazarus over Delphi ever since I started doing FPC aeons ago  :o :)

Frank

  • Jr. Member
  • **
  • Posts: 62
Re: Change the class name of TForm on win32 ?
« Reply #9 on: December 26, 2015, 10:52:42 pm »
Lazarus 1.7 Revision 51009 w/Fpc-3.0.0 32bit On Win7 64bit

I too have this issue. Lazarus forces me to use Window Caption for Win32 FindWindow which is not the best... Using classname would be safer...

vhanla

  • New Member
  • *
  • Posts: 13
Re: Change the class name of TForm on win32 ?
« Reply #10 on: June 04, 2017, 10:35:47 pm »
Is there any update on this inconvenience?

I have to use a script/program that changes win32int.pp file contents changing constants:
clsname and clsnamew values according to my needs, since CreateParams WinClassName is not used anywhere.

BTW win32object.inc is the only one using clsnameW

I just replaced win32wsforms.pp pClassName := @AParams.WinClassName[0]; but application also needs win32object.inc's clsnamew to be the same as clsname, otherwise it will raise exception and won't continue creating any form.

I'm not sure if this clsname or clsnamew affects only a form's window or others as well.

This will sound stupid, but if there is no plans to fix that inconvenience, at least on projects options it might be great to add WinClassName and according to that, update win32int.pp contents  >:D

Thaddy

  • Hero Member
  • *****
  • Posts: 8880
Re: Change the class name of TForm on win32 ?
« Reply #11 on: June 05, 2017, 07:14:02 am »
The static names referred to here are part of the windows API class names, not Lazarus. These are a completely different set of class: win32 API control class.
This is the case in any language e.g.:
Code: C  [Select]
  1. HWND hwndButton = CreateWindow(
  2.     L"BUTTON",  // Predefined class; Unicode assumed
  3.     L"OK",      // Button text
  4.     WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles
  5.     10,         // x position
  6.     10,         // y position
  7.     100,        // Button width
  8.     100,        // Button height
  9.     m_hwnd,     // Parent window
  10.     NULL,       // No menu.
  11.     (HINSTANCE)GetWindowLong(m_hwnd, GWL_HINSTANCE),
  12.     NULL);      // Pointer not needed.

Do not change them and do not confuse windows API control classes with Object Pascal widget classes. The windows messaging system will get broken.

@Leledumbo
Those are the windows control classes. and win32int.pp: is part of the windows api. There are two sets: unicode16 and ansi. Do not change.
« Last Edit: June 05, 2017, 07:18:00 am by Thaddy »
Most people that want to use threading should learn to patch their jeans first: use a needle.

vhanla

  • New Member
  • *
  • Posts: 13
Re: Change the class name of TForm on win32 ?
« Reply #12 on: June 05, 2017, 04:42:00 pm »
So, is there a proper way to set a different WinClassName than 'Window'#0 ? All Lazarus applications (windows) has that ClassName.

Thaddy

  • Hero Member
  • *****
  • Posts: 8880
Re: Change the class name of TForm on win32 ?
« Reply #13 on: June 05, 2017, 05:18:33 pm »
So, is there a proper way to set a different WinClassName than 'Window'#0 ? All Lazarus applications (windows) has that ClassName.
Yes you can but 'Window#0' is defined by the OS (Windows) so leave it alone.
You must subclass and registerclass through the windows API and that (although - I think - easy - not many do...) takes a lot of code, including createparams, painting, resource handling and message handling in general.
Simply the wrong way to do what you want. Checkout Charley Calvert's windows programming book for that.

There are some options that are kind of a mix of Object Pascal and Windows API handling, but it looks awful and is just a shortcut for a program... not for a re-usable component, though.
« Last Edit: June 05, 2017, 05:26:24 pm by Thaddy »
Most people that want to use threading should learn to patch their jeans first: use a needle.

vhanla

  • New Member
  • *
  • Posts: 13
Re: Change the class name of TForm on win32 ?
« Reply #14 on: June 06, 2017, 02:48:36 am »
I thought overriding CreateParams as in Delphi might be enough. Thank you for your answer and clarifying my doubts.