Recent

Author Topic: [SOLVED] Q: method replacement for MakeObjectInstance Win x64?  (Read 5313 times)

d7_2_laz

  • Hero Member
  • *****
  • Posts: 510
From an app Delphi 7 / Win x32 i had the code:
Code: Pascal  [Select][+][-]
  1. procedure TMyCustomListView.InitFDragControl;
  2. var WinCtl: TWinControl;
  3. begin
  4.    if Owner is TWinControl then begin
  5.       WinCtl := TWinControl( Owner );
  6.       FWndHandle := WinCtl.Handle;
  7.       FWndProcInstance := MakeObjectInstance( WndProcSubclassed );

and with Lazarus 2.0.12 Win x64 i got an exception on the last line (MakeObjectInstance).

From an other thread in the forum i did read that's implemented with Win32, but for Win64 it's only a stub that throws an exception. And in fact in source\rtl\win64\classes.pp it does read:
Code: Pascal  [Select][+][-]
  1. function MakeObjectInstance(Method: TWndMethod): Pointer;
  2.   begin
  3.     runerror(211);
  4.     MakeObjectInstance:=nil;
  5.   end;

As from other threads within the forum it did not really got the clue: what might be the recommended technique to replace the MakeObjectInstance now?
Thanks a lot for any feedback in advance!

« Last Edit: April 16, 2021, 05:28:36 pm by d7_2_laz »
Lazarus 3.2  FPC 3.2.2 Win10 64bit

Bi0T1N

  • Jr. Member
  • **
  • Posts: 85
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #1 on: April 12, 2021, 03:17:29 pm »
From an other thread in the forum i did read that's implemented with Win32, but for Win64 it's only a stub that throws an exception. And in fact in source\rtl\win64\classes.pp it does read:
Code: Pascal  [Select][+][-]
  1. function MakeObjectInstance(Method: TWndMethod): Pointer;
  2.   begin
  3.     runerror(211);
  4.     MakeObjectInstance:=nil;
  5.   end;
Correct, seems it was never really implemented for Win64. I believe a similar approach as for Win32 should also work for Win64.
Better create an issue for it on the bugtracker.

As from other threads within the forum it did not really got the clue: what might be the recommended technique to replace the MakeObjectInstance now?
Which thread do you mean?

d7_2_laz

  • Hero Member
  • *****
  • Posts: 510
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #2 on: April 12, 2021, 03:30:46 pm »
There are some iinteresting references when searching in the forums for the topic "MakeObjectInstance ", eg.
https://forum.lazarus.freepascal.org/index.php/topic,37930.msg256385.html#msg256385
https://forum.lazarus.freepascal.org/index.php/topic,22974.msg136564.html#msg136564
https://forum.lazarus.freepascal.org/index.php/topic,51259.msg376038.html#msg376038
But some of them are very old, and so i have no idea what's the current state. So maybe somebody dows know more about?
Lazarus 3.2  FPC 3.2.2 Win10 64bit

d7_2_laz

  • Hero Member
  • *****
  • Posts: 510
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #3 on: April 12, 2021, 05:14:50 pm »
Directyl applying the Win32 coding won't work (that's just what i had expected),
because a lot of other stuff (structures and callbacks) are needed as well as some assembler code
which fails to compile (at:  call %ecx    and at: popl %eax). So that's probably not the right way to go..
Lazarus 3.2  FPC 3.2.2 Win10 64bit

ASerge

  • Hero Member
  • *****
  • Posts: 2222
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #4 on: April 12, 2021, 08:58:36 pm »
As from other threads within the forum it did not really got the clue: what might be the recommended technique to replace the MakeObjectInstance now?
MakeObjectInstance is a thread-safe version of the WndMethod wrapper without creating a window. If you are not confused by a hidden window for the same purpose, use LCLIntf.AllocateHWnd.
In your case, you should also pay attention to the function SetWindowSubclass.

d7_2_laz

  • Hero Member
  • *****
  • Posts: 510
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #5 on: April 12, 2021, 09:58:30 pm »
Hello ASerge,
thank you for your feedback, it's appreciated a lot!

I already did try it, alternatively, with AllocateHwnd (no i don't care about it's an invisible Window), but yet without success. But so i continue to dig here resp. with SetWindowSubclass.
Lazarus 3.2  FPC 3.2.2 Win10 64bit

Bi0T1N

  • Jr. Member
  • **
  • Posts: 85
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #6 on: April 13, 2021, 11:25:51 am »
Directyl applying the Win32 coding won't work (that's just what i had expected),
because a lot of other stuff (structures and callbacks) are needed as well as some assembler code
which fails to compile (at:  call %ecx    and at: popl %eax). So that's probably not the right way to go..
You need to adapt the asm to follow the x64 calling convention and also to use the 64-bit registers (otherwise the register values are pointing to wrong addresses if you call them). Thus simply copying the Win32 asm won't work.
The TMethodWrapperTrampoline declaration should also be adapted as it uses PtrInt which shouldn't be used according to the recent documentation (also for Win32).
Do you've a small example that could be used for tests?

d7_2_laz

  • Hero Member
  • *****
  • Posts: 510
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #7 on: April 13, 2021, 01:37:43 pm »
No, unfortunately i don't have a simple case, but can describe the purpose and context in short (and as well the concerns about i have).
It's simply for to receive WM_DROPFILES message passed from outside of the app. That one wouldn't be catched by the default WndPro message loopc.
Yes: i just  got aware (by another thread from ASerge) that MSDN mentions that WM_DROPFILES should  be avoided for that if possible https://docs.microsoft.com/en-us/windows/win32/shell/datascenarios
So i'm thinking about to do it completelydifferent, maybe following the Wiki https://wiki.freepascal.org/Drag_and_Drop_sample

But for to complete this loop for the moment: could such be done with an AllocateHwnd resp. SetWindowSubclass too? (Probablyy, but i did not have the time to test yet).  Assembler code fixing wouldn't be the preferred option thogh.

Code: Pascal  [Select][+][-]
  1. procedure TMyCustomListView.InitFDragControl;
  2. var WinCtl: TWinControl;
  3. begin
  4.    if Owner is TWinControl then  begin
  5.       // Subclass; the owner so this control can capture the WM_DROPFILES message
  6.       WinCtl := TWinControl( Owner );
  7.       FWndHandle := WinCtl.Handle;
  8.      /FWndProcInstance := MakeObjectInstance( WndProcSubclassed );  // Lazarus: leads to exception due to stub. - FWndProcInstance is Pointer
  9.       FDefProc := Pointer( GetWindowLong( FWndHandle, GWL_WNDPROC )); // Store original WndProc ...
  10.       SetWindowLong( FWndHandle, GWL_WNDPROC, Longint( FWndProcInstance ));
  11.    end
  12.    else
  13.     FEnabled := False;
  14. end;
  15.  
  16. procedure TMyCustomListView.WndProcSubclassed( var Msg: TMessage );
  17. begin
  18.   with Msg do begin
  19.     if Msg = WM_DROPFILES then
  20.        DropFiles( HDrop( wParam ))
  21.     else
  22.        Result := CallWindowProc( FDefProc, FWndHandle, Msg, WParam, LParam);
  23.   end;
  24. end;
Lazarus 3.2  FPC 3.2.2 Win10 64bit

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #8 on: April 13, 2021, 08:55:03 pm »
It's simply for to receive WM_DROPFILES message passed from outside of the app. That one wouldn't be catched by the default WndPro message loopc.

Doesn't your custom ListView have its own window?  Why are you subclassing the Owner's window, instead of registering the ListView's own window?  Also consider what happens if the Owner's window has to be re-created at runtime after you have subclassed it.  This is easier to handle if you use your own window.

In any case, you should use SetWindowSubclass() instead of SetWindowLong(GWL_WNDPROC) (see Safer subclassing).  You can pass the Self pointer as a parameter to pass into the classback, so you wouldn't even need to use MakeObjectInstance() at all.

Code: Pascal  [Select][+][-]
  1. function WndProcSubclassed(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM; uIdSubclass: UINT_PTR; dwRefData: DWORD_PTR): LResult; stdcall;
  2. begin
  3.   case uMsg of
  4.     WM_DROPFILES: TMyCustomListView(dwRefData).DropFiles( HDrop( wParam ));
  5.     WM_NCDESTROY: RemoveWindowSubclass(hWnd, @WndProcSubclassed, uIdSubclass);
  6.   end;
  7.   Result := DefSubclassProc(hWnd, uMsg, wParam, lParam);
  8. end;
  9.  
  10. procedure TMyCustomListView.InitFDragControl;
  11. var WinCtl: TWinControl;
  12. begin
  13.   if Owner is TWinControl then  begin
  14.     // Subclass; the owner so this control can capture the WM_DROPFILES message
  15.     WinCtl := TWinControl( Owner );
  16.     FWndHandle := WinCtl.Handle;
  17.     SetWindowSubclass(FWndHandle, @WndProcSubclassed, 1, DWORD_PTR(Self));
  18.   end
  19.   else
  20.     FEnabled := False;
  21. end;

Yes: i just  got aware (by another thread from ASerge) that MSDN mentions that WM_DROPFILES should  be avoided for that if possible https://docs.microsoft.com/en-us/windows/win32/shell/datascenarios

Yes, it is better to implement the IDropTarget interface than handling the WM_DROPFILES message.
« Last Edit: April 13, 2021, 09:05:53 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

d7_2_laz

  • Hero Member
  • *****
  • Posts: 510
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #9 on: April 13, 2021, 11:53:50 pm »
Hello Remy, thank you a lot!

Why subclassing the Owner's window? Well, that's i found in the code, and i interpreted it's needed because that one would receive the message (it did work in fact using MakeObjectInstance)
The custom listview has an own window, but the default WndProc never did receive the WM_DROPFILES nessage (i retested that in den Delphi 7 version)
 
Meanwhile i had have a couple of tests (unfortunately i had not much time left today), and those are, in short, the results:

Code: Pascal  [Select][+][-]
  1.      WinCtl := TWinControl( Owner );
  2.      FWndHandle := WinCtl.Handle;
  3.  
  4.      FMessageSubClassedHandle := AllocateHWnd(WndProcSubclassed);  // FMessageSubClassedHandle: HWnd
  5.      FMessageSubClassedProc := Pointer( GetWindowLong( FMessageSubClassedHandle, GWL_WNDPROC )); // FMessageSubClassedProc : Pointer
  6.  
  7. // Attempt 1:  ----> would lead to exception. Maybe due to wrong data types. Didn't pursue that further yet
  8.       //SetWindowLong( FWndHandle, GWL_WNDPROC, Longint( FMessageSubClassedProc ));// For_subclassed
  9.  
  10. // Attempt 2a: -----> receives only WM_ACTIVATEAPP (or some Message.Msg 799 / unknown)
  11.       //SetWindowSubclass(FMessageSubClassedHandle, FMessageSubClassedProc, 1, DWORD_PTR(Self) );
  12. // Attempt 2b:  ----> compöiler error: Variable identifier expected
  13.       //SetWindowSubclass(FWndHandle, @WndProcSubclassed, 1, DWORD_PTR(Self) );
  14. // Attempt 2c:  ----> result same as 2a (mostly WM_ACTIVATEAPP)
  15.       //SetWindowSubclass(FWndHandle, FMessageSubClassedProc, 1, DWORD_PTR(Self) );
  16. // Attempt 2d:  ----> result same as 2a (mostly WM_ACTIVATEAPP)
  17.       //SetWindowSubclass(Application.Handle, FMessageSubClassedProc, 1, DWORD_PTR(Self) );
  18.  

In short: the best i could have until now were a couple of "WM_ACTIVATEAPP ".

Tried now to use the callback function as a standalone function (not a class function) just like you Remy printed it.
I called it "WndProcSubclassed2" here for to distinct it by a different name.
Ii did compile without complaints (other than attempt 2 b).

Code: Pascal  [Select][+][-]
  1. // Attempt 2e:  ----> result same as 2a (receives only WM_ACTIVATEAPP (or some Message.Msg 799 / unknown); else nothing
  2.      SetWindowSubclass(FWndHandle, @WndProcSubclassed2, 1, DWORD_PTR(Self) );

So meanwhile i suspect that the LCL maybe does not pass the message to the custom controls.
That means, it would be not simply better to avoid this message , but it is even not possible to work with it.
May it be the case that this approach is not possible by principle?
The object hierarchy in my case is Form -> Panel -> PageControl -> TabSheet -> custom listview
Lazarus 3.2  FPC 3.2.2 Win10 64bit

d7_2_laz

  • Hero Member
  • *****
  • Posts: 510
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #10 on: April 14, 2021, 01:20:54 am »
Stop ...  regarding the test of attempt #2e - this is using the stand-alone "function WndProcSubclassed"  as you (Remy) mentioned, i did a work error.  I can confirm that it receives the belonging message!

Code: Pascal  [Select][+][-]
  1. procedure TMyCustomListView.WndProcSubclassed( var Msg: TMessage );
  2. ......
  3.  
  4. function WndProcSubclassed2(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM; uIdSubclass: UINT_PTR; dwRefData: DWORD_PTR): LResult; stdcall;
  5. ..................
  6.  
  7. // That had not compiled ("Variable identifier expected"):
  8.       SetWindowSubclass(FWndHandle, @WndProcSubclassed, 1, DWORD_PTR(Self) );
  9.                                  // This rpresents my previous version of the callback
  10.  
  11. // This does compile, and the message iWM_DROPFILES)
  12. // sent from an outer application is received:
  13.       SetWindowSubclass(FWndHandle, @WndProcSubclassed2, 1, DWORD_PTR(Self) ) ;
  14.                                  // Represents the callback function as of Remy
  15.  

So i can say that with the help of this sample the originial question (what does replace the obsolete function MakeObjectInstance ?)  is solved. That is great!

Lazarus 3.2  FPC 3.2.2 Win10 64bit

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #11 on: April 14, 2021, 05:46:57 pm »
Why subclassing the Owner's window? Well, that's i found in the code, and i interpreted it's needed because that one would receive the message (it did work in fact using MakeObjectInstance)
The custom listview has an own window, but the default WndProc never did receive the WM_DROPFILES nessage (i retested that in den Delphi 7 version)

If you register the ListView's own window (via DragAcceptFiles() or the WS_EX_ACCEPTFILES window style), and then drop files onto the ListView, then the ListView's own WndProc will receive the WM_DROPFILES message.  There is no need to handle the message in the Owner's WndProc.

Meanwhile i had have a couple of tests (unfortunately i had not much time left today), and those are, in short, the results:

Code: Pascal  [Select][+][-]
  1.      WinCtl := TWinControl( Owner );
  2.      FWndHandle := WinCtl.Handle;
  3.  
  4.      FMessageSubClassedHandle := AllocateHWnd(WndProcSubclassed);  // FMessageSubClassedHandle: HWnd
  5.      FMessageSubClassedProc := Pointer( GetWindowLong( FMessageSubClassedHandle, GWL_WNDPROC )); // FMessageSubClassedProc : Pointer

AllocateHWnd() creates a hidden window that the user will never see it, let alone ever drop files onto, so its WndProc will never see any WM_DROPFILES messages (unless you catch them elsewhere and then SendMessage() them to the FMessageSubClassedHandle window).

And there is never a good reason to ever subclass a window that is created by AllocateHWnd(), since you are providing it with your own WndProc as an input parameter to begin with.  If you need that WndProc to be overriddable, make it virtual.

Code: Pascal  [Select][+][-]
  1. // Attempt 1:  ----> would lead to exception. Maybe due to wrong data types. Didn't pursue that further yet
  2.       //SetWindowLong( FWndHandle, GWL_WNDPROC, Longint( FMessageSubClassedProc ));// For_subclassed

More likely because you are not subclassing the original WndProc of FWndHandle, you are just flat out replacing it and not saving the original WndProc, so any unprocessed messages are not going to be passed to the original.

Code: Pascal  [Select][+][-]
  1. // Attempt 2a: -----> receives only WM_ACTIVATEAPP (or some Message.Msg 799 / unknown)
  2.       //SetWindowSubclass(FMessageSubClassedHandle, FMessageSubClassedProc, 1, DWORD_PTR(Self) );

Makes sense, since FMessageSubClassedHandle is a hidden window, so it is not going to see very many messages, typically only system messages targetting top-level windows.

Code: Pascal  [Select][+][-]
  1. // Attempt 2b:  ----> compöiler error: Variable identifier expected
  2.       //SetWindowSubclass(FWndHandle, @WndProcSubclassed, 1, DWORD_PTR(Self) );

You can't use a non-static class method for SetWindowSubclass() (or for GWL_WNDPROC unless MakeObjectInstance() is used for that).

Code: Pascal  [Select][+][-]
  1. // Attempt 2c:  ----> result same as 2a (mostly WM_ACTIVATEAPP)
  2.       //SetWindowSubclass(FWndHandle, FMessageSubClassedProc, 1, DWORD_PTR(Self) );
  3. // Attempt 2d:  ----> result same as 2a (mostly WM_ACTIVATEAPP)
  4.       //SetWindowSubclass(Application.Handle, FMessageSubClassedProc, 1, DWORD_PTR(Self) );

You can't use a WndProc from GWL_WNDPROC as the callback for SetWindowSubclass().  They are completely different function signatures.

So meanwhile i suspect that the LCL maybe does not pass the message to the custom controls.

I'm not familiar with LCL's internals to comment on that.  I know in Delphi, this would not be an issue under VCL, as every TWinControl has its own WndProc and controls are able to receive all window messages that are sent directly to controls.  Whereas under FMX, child controls are not windowed at all, so all window messages go through a TForm's WndProc and are heavily filtered and require subclassing to do custom processing.  Maybe LCL is more like FMX than VCL in that regard?  I don't know.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

d7_2_laz

  • Hero Member
  • *****
  • Posts: 510
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #12 on: April 15, 2021, 03:59:11 pm »
Hello Remy,
thank you a lot for your very detailed response!
As i'm not as far so indepth those usbclassing matters as you are, let me try to summarize my understanding of the proceeding of the component:

In fact, receiving of drops is activated via DragAcceptFiles here.
As parameter, the handle of the owner (eg. a panel) has been spent, as this is a wincontrol, and the the DragAcceptFiles won't accept the handle of a custom listview as parameter (exception)
For that reason - this is my assumption - it's done somehow/roughly like such:
Code: Pascal  [Select][+][-]
  1. constructor TMyCustomListView.Create(AOwner: TComponent);
  2. var WinCtl: TWinControl;
  3. begin
  4.    ...
  5.      WinCtl := TWinControl( AOwner );
  6.      FWndHandle := WinCtl.Handle;
  7.   DragAcceptFiles( FWndHandle, True );
  8.  // DragAcceptFiles( Self.Handle, True );   // --> exception
  9.  

As result of that, the winproc of the owner (eg. a panel) will receive the drop message, but not the winproc of the custom listview

Code: Pascal  [Select][+][-]
  1.   TMyCustomListView = class(TCustomListView)
  2.     protected
  3.        procedure WndProc( var Message: TMessage ); override;
  4.   ...
  5. procedure TMyCustomListView.WndProc(var Message: TMessage);
  6. begin
  7.   with Message do begin
  8.     Case Msg Of
  9.       WM_CREATE : ShowMessage('WndProc: received WM_CREATE');          // --> will be called
  10.       WM_DROPFILES : ShowMessage('WndProc: received WM_DROPFILES');    // --> will NOT be triggered by an outside drop
  11.  

Due to that - so my understanding- the component introduced the subclassing bound to the owner.
In fact the drop message could be received now fine. And the processing of listview messages is not negatively touched either.
At the end of the process, the window proc had been restored to the original one.
But so - as you directly noticed   :-)  , the reference is not pointing to the custom listview proc, but to the proc of the owner.
Maybe, that's what i'm thinking now, the DragAcceptFiles could have a listview-xyz as parameter, so that this whole detour is not necessary perhaps. And proabbly it had been more appropriate to let the two message loops distinct rather than to do tht subclassing.

I'm myself not emphasized about this construct, but that had been the context i had when i found that MakeObjectInstance threw an error, which leaded to my OP.

Apparently .... meanwhile it's overdue to have a small test project for that.
i created one, which is minimalistic shrinked to the topic in speech.
- It does not contain more than to open a message box if the drop message is passed to an (empty) custom listview.
- Accompanying with the suffix "_0" is the same --> but without the subclassing stuff .... only with a simple listview winproc.
  With no messagebox appearing here of course, because the Drop is registered for the owner.
Both projects are Delphi (7) of course.
As for Lazarus a possible solutinn had been just discussed above. I'm happy with that. The more, as i meanwhile did read somewhere, probably Embarcadero did mark the MakeObjectInstance as a deprecated procedure.
Lazarus 3.2  FPC 3.2.2 Win10 64bit

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #13 on: April 15, 2021, 06:06:52 pm »
In fact, receiving of drops is activated via DragAcceptFiles here.
As parameter, the handle of the owner (eg. a panel) has been spent, as this is a wincontrol, and the the DragAcceptFiles won't accept the handle of a custom listview as parameter (exception)

What kind of exception? That would imply that either:

* the TCustomListView.Handle is not a Win32 HWND but something else, which according to documentation (here, here, and here) it should be an HWND on Windows, but I do seem to now recall seeing that may not always be the case.

* the Handle is not available.

For that reason - this is my assumption - it's done somehow/roughly like such:

Here is an interesting tidbit I just found:

Handling WM_DROPFILES message doesn't work in Lazarus

Which provides an outline of how message dispatching works under LCL, and suggests a couple of different ways to handle WM_DROPFILES on a per-control basis.

  With no messagebox appearing here of course, because the Drop is registered for the owner.
Both projects are Delphi (7) of course.

There is no need to subclass the Owner window in Delphi, since the ListView (and any TWinControl) has its own HWND and can receive WM_DROPFILES messages directly, there is no intermediate message filtering being done, like LCL apparently does.

The more, as i meanwhile did read somewhere, probably Embarcadero did mark the MakeObjectInstance as a deprecated procedure.

It is not deprecated.  It is still used extensively by every VCL TWinControl-based component, and various non-windowed components (TTimer, etc).  However, MakeObjectInstance() was originally implemented in the Forms unit, and then was moved in Delphi 6 to the Classes unit.  It is only the Forms version that is deprecated, not the Classes version.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

d7_2_laz

  • Hero Member
  • *****
  • Posts: 510
Re: Q: method replacement for MakeObjectInstance Win x64?
« Reply #14 on: April 16, 2021, 05:04:01 pm »
Which Exception?  EInvalidOperation  (caseof Delphi)
.... after a couple of minutes i realized. hey, that's normal, it (the call of DragAcceptFiles) is done within the constructor = the handle is not yet accomplished!
That changed all (for Delphi)  Within the original source of the component i see a very big constructor and one item of it is the harmless " DragAcceptFiles( FWndHandle, True );
", where FWndHandle is the handle of the owner. ...  because with Self.Handle it crashes .... which leads to the subclass story referring the owner.
In fact (in Delphi) it's more easily possible to do after the Create:
Code: Pascal  [Select][+][-]
  1.    MyCustomListView1 := TMyCustomListView.Create(Self);
  2.    with MyCustomListView1 do begin
  3.        Parent := Panel1;
  4.        Align := alClient;
  5.        SetActivateDropAccept(True);    // (or done via property, eg- ActivateDropAccept := True;
  6. ....      
  7. procedure TMyCustomListView.SetActivateDropAccept(Value: Boolean);
  8. begin
  9.   DragAcceptFiles( Handle, True );
  10. end;
  11.  

Now, the app will receive the message via WndPro or via "procedure WMDropFiles(var Msg: TMessage); message WM_DROPFILES;" or by whatsover
No subclass needed.

I imported the mini project to Lazarus and, first,  indeed it did NOT work.
As explained at diverse places (eg. in the stakoverflow-link yoo (Remy) mentioned) it will be a victim of the DeliverMessage implementation.
Obviously this is the foreseen exit for an delivery of the message here: the callback "FormDropFiles" in the MainForm or it's equivalent for a component.

Remark.: from an encapsulation point of view i don't like the idea that a component needs to rely on settings of a layer outside, the Mainform or Application. Better for me a component might set the required property by itself, or nearby.
For the custom listview, i found the equivalent OnDropFiles property.

So this ends up that the origin of the problem (the need of subclassing and, so, for MakeObjectInstance) became clear
and better solutions for that are available in Delphi as well as with Lazarus.
Lazarus:
Code: Pascal  [Select][+][-]
  1.    MyCustomListView1 := TMyCustomListView.Create(Self);
  2.    with MyCustomListView1 do begin
  3.        Parent := Panel1;
  4.        Align := alClient;
  5.        //SetActivateDropAccept(True); // or via property, like ActivateDropAccept := True;
  6.        // Replaced by:
  7.        OnDropFiles := DoOnDropFiles;  // Symtax: Mode Delphi
  8.        // Working with OnDropFiles doesn't require DragAcceptFiles any longer,
  9.        // but does require AllowDropFiles:= True
  10.    end;
  11.    AllowDropFiles:= True;  // Lazarus (Delphi does not know this property)
  12.  
  13. procedure TMyCustomListView.DoOnDropFiles(Sender: TObject;const FileNames: array of String);
  14. begin
  15.   ShowMessage('MyCustomListView -  DoOnDropFiles');
  16. end;


---> The two mini demo projects are attached.

Lazarus 3.2  FPC 3.2.2 Win10 64bit

 

TinyPortal © 2005-2018