Recent

Author Topic: [SOLVED] Update ChangeWindowMessageFilter to ChangeWindowMessageFilterEx  (Read 2050 times)

valter.home

  • Jr. Member
  • **
  • Posts: 81
I need some suggestions as I am not very knowledgeable about using messages.
I found this topic:
https://forum.lazarus.freepascal.org/index.php/topic,18620.msg105268.html#msg105268
that it uses ChangeWindowMessageFilter to allow Drag and Drop to an application with elevated privileges. It works fine.
According to Microsoft, however, it would be better to use ChangeWindowMessageFilterEx as the previous one could be removed in a short time.
So I tried to update the code but it doesn't work. I'm definitely wrong. Does anyone have time to check it out?

Code: Pascal  [Select][+][-]
  1. const
  2.   MSGFLT_ALLOW = 1;
  3.   MSGFLT_DISALLOW = 2;
  4.   MSGFLT_RESET = 0;
  5.  
  6. type
  7.   TChangeFilterStruct = packed record
  8.     cbSize: DWORD;
  9.     ExtStatus: DWORD;
  10.   end;
  11.   PChangeFilterStruct = ^TChangeFilterStruct;
  12.  
  13. type
  14.   TChangeWindowMessageFilterEx = function(hwnd: HWND; msg: Cardinal; Action: Dword; ChangeFilterStruct: PChangeFilterStruct): BOOL; stdcall;
  15.  
  16. var
  17.   HForm: THandle;
  18.   User32Module: THandle;
  19.   ChangeWindowMessageFilterPtr: Pointer;
 

Code: Pascal  [Select][+][-]
  1. function CheckUser32Module: Boolean;
  2. begin
  3.  if User32Module=0 then User32Module:=safeLoadLibrary('USER32.DLL');
  4.  Result:=User32Module>HINSTANCE_ERROR;
  5. end;
  6.  

Code: Pascal  [Select][+][-]
  1. function CheckUser32ModuleFunc(const Name: string; var ptr: Pointer): Boolean;
  2. begin
  3.  Result:=CheckUser32Module;
  4.  if Result then
  5.   begin
  6.    ptr:=GetProcAddress(User32Module, PChar(Name));
  7.    Result:=Assigned(ptr);
  8.    if not Result then
  9.    begin
  10.      ptr:=Pointer(1);
  11.    end;
  12.   end;
  13. end;
  14.  

Code: Pascal  [Select][+][-]
  1. function ChangeWindowMessageFilterEx(hwnd: HWND; msg: Cardinal; Action: Dword; ChangeFilterStruct: PChangeFilterStruct): BOOL;
  2. begin
  3.  if (Integer(ChangeWindowMessageFilterPtr) > 1) or
  4.   CheckUser32ModuleFunc('ChangeWindowMessageFilterEx', ChangeWindowMessageFilterPtr) then
  5.    begin
  6.  Result:=TChangeWindowMessageFilterEx(ChangeWindowMessageFilterPtr) (hwnd, Cardinal(msg), action, nil);
  7.    end
  8.  else Result:=false;
  9. end;  

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormCreate(Sender: TObject);
  2.   const
  3.     WM_COPYGLOBALDATA = $0049;
  4. begin
  5.   try
  6.     HForm:=application.MainFormHandle;
  7.     ChangeWindowMessageFilterEx(HForm, WM_COPYDATA, MSGFLT_ALLOW, nil);
  8.     ChangeWindowMessageFilterEx(HForm, WM_DROPFILES, MSGFLT_ALLOW, nil);
  9.     ChangeWindowMessageFilterEx(HForm, WM_COPYGLOBALDATA , MSGFLT_ALLOW, nil);
  10.   finally
  11.     //
  12.   end;
  13. end;

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormDropFiles(Sender: TObject; const FileNames: array of String
  2.   );
  3. begin
  4.   showmessage('OK');
  5. end;

« Last Edit: April 15, 2021, 10:19:36 am by valter.home »

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Update ChangeWindowMessageFilter to ChangeWindowMessageFilterEx
« Reply #1 on: April 14, 2021, 11:16:52 am »
According to Microsoft, however, it would be better to use ChangeWindowMessageFilterEx as the previous one could be removed in a short time.
If I were you, I wouldn't worry about that.  That function has been available since Windows Vista.  Getting rid of it now has the potential to break a fair amount of user code and MS really avoids doing that but, they are really good at scaring people into not using one function or another.

All that said, MS may get rid of the function 10 or 15 years from now (and that's a maybe considering that utterly useless functions such as LocalLock and other LocalXXX are still around.)

HTH.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

valter.home

  • Jr. Member
  • **
  • Posts: 81
Re: Update ChangeWindowMessageFilter to ChangeWindowMessageFilterEx
« Reply #2 on: April 14, 2021, 11:44:06 am »
Thanks for your opinion. If I don't solve the problem then I'll use ChangeWindowMessageFilter.
But as for my code, do you have any idea where I'm doing wrong?

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Update ChangeWindowMessageFilter to ChangeWindowMessageFilterEx
« Reply #3 on: April 14, 2021, 12:12:23 pm »
But as for my code, do you have any idea where I'm doing wrong?
Not off hand but, your code isn't checking that the result of calling the function is "true", if it isn't then you should get the last error (GetLastError) immediately after calling the function, that might give some clue as to what the problem is.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Update ChangeWindowMessageFilter to ChangeWindowMessageFilterEx
« Reply #4 on: April 14, 2021, 12:13:44 pm »
Notice that if you find user32 or kernel32 functions missing, a small bugreport (and maybe even a.... patch) into bugrepo will be appreciated.

valter.home

  • Jr. Member
  • **
  • Posts: 81
Re: Update ChangeWindowMessageFilter to ChangeWindowMessageFilterEx
« Reply #5 on: April 14, 2021, 12:50:05 pm »
Quote
your code isn't checking that the result of calling the function is "true"

Great! Thanks.

Code: Pascal  [Select][+][-]
  1. if not ChangeWindowMessageFilterEx(HForm, WM_DROPFILES, MSGFLT_ALLOW, nil) then
  2.     Memo1.Lines.Add(SysErrorMessage(GetLastError));

And the mystery is revealed:

Code: Pascal  [Select][+][-]
  1. Invalid window handle

I tried to move the code from OnCreate to OnShow and now it works fine.
So in the OnCreate event of the form the window handle is not yet available? The few examples found use the OnCreate event itself.


440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Update ChangeWindowMessageFilter to ChangeWindowMessageFilterEx
« Reply #6 on: April 14, 2021, 01:17:21 pm »
Great! Thanks.
So in the OnCreate event of the form the window handle is not yet available? The few examples found use the OnCreate event itself.
You're welcome.  As far as what OnCreate does and has available, I simply have no idea.  I write all my code directly to the Windows API, as a result I know nothing about all the OnWhatever messages in FPC and Delphi.

Hopefully, someone else can answer that question.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: Update ChangeWindowMessageFilter to ChangeWindowMessageFilterEx
« Reply #7 on: April 14, 2021, 06:00:28 pm »
I tried to move the code from OnCreate to OnShow and now it works fine.
So in the OnCreate event of the form the window handle is not yet available? The few examples found use the OnCreate event itself.

I can't really answer that, but my gut says the problem is that the Application.MainForm hasn't been assigned yet when the MainForm's OnCreate event is fired, so there is nothing for Application.MainFormHandle to return yet.

If TForm1 is your MainForm, then there is no need to use Application.MainFormHandle in the Form's own events.  Use the Form's own Handle property instead:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. const
  3.   WM_COPYGLOBALDATA = $0049;
  4. begin
  5.   ChangeWindowMessageFilterEx(Handle, WM_COPYDATA, MSGFLT_ALLOW, nil);
  6.   ChangeWindowMessageFilterEx(Handle, WM_DROPFILES, MSGFLT_ALLOW, nil);
  7.   ChangeWindowMessageFilterEx(Handle, WM_COPYGLOBALDATA, MSGFLT_ALLOW, nil);
  8. end;

However, when it comes to per-window registrations, I would suggest overriding the Form's virtual CreateWnd() method instead.  That way, the registrations can also survive window recreations, too.

Code: Pascal  [Select][+][-]
  1. protected
  2.   procedure CreateWnd; override;
  3.  
  4. procedure TForm1.CreateWnd;
  5. const
  6.   WM_COPYGLOBALDATA = $0049;
  7. begin
  8.   inherited;
  9.   ChangeWindowMessageFilterEx(Handle, WM_COPYDATA, MSGFLT_ALLOW, nil);
  10.   ChangeWindowMessageFilterEx(Handle, WM_DROPFILES, MSGFLT_ALLOW, nil);
  11.   ChangeWindowMessageFilterEx(Handle, WM_COPYGLOBALDATA, MSGFLT_ALLOW, nil);
  12. end;
« Last Edit: April 14, 2021, 06:07:54 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

valter.home

  • Jr. Member
  • **
  • Posts: 81
Re: Update ChangeWindowMessageFilter to ChangeWindowMessageFilterEx
« Reply #8 on: April 14, 2021, 09:15:44 pm »
Quote
Application.MainForm hasn't been assigned yet

I confirm that you are right, using Form's Handle instead of Application.MainFormHandle the code is also executed in the OnCreate event.

However I followed your advice using the CreateWnd() method.

Thanks for your support.

 

TinyPortal © 2005-2018