Recent

Author Topic: Shell contextmenu, issue with certain submenues resp. with HandleMenuMsg  (Read 572 times)

d7_2_laz

  • Full Member
  • ***
  • Posts: 109
I’m near by to finish my port of a Delphi7 app to Lazarus (2.0.12)  Windows x64,  but at the end I had to notice a certain flaw where I’m now missing the clue.

I ported a files&folders presenting listview (not shell listview, but that does not play a role) context menu and found that I basically works fine, also for certain submenues, like “SendTo”.
But …  other submenues (like “Open with …”) stayed empty.
So the question is why the handler for those submenues do not succeed.
The failing result is the same in Delphi 7 when i deactivate the call of the ContextMenu2: //ICM2.HandleMenuMsg(Msg, wParam, lParam).

Looking onto the result of this HandleMenuMsg in my Lazarus port I find that the result value is: 2147500037 (googling hat error code you’ll find hits which are misleading in my eyes).
(btw I saw that wParam had been (mostly) empty when doing this call).

Researching I find that my coding is essentially near to that one mentioned as example by ASerge in reply #3 in: https://forum.lazarus.freepascal.org/index.php/topic,33486.msg218043.html#msg218043
So one might take this coding as a code reference for my description of the issue.

Of course it is better to spend a test case for that.
I decided to create one using the code sample mentioned, although it is for a shell treeview.
I assume I can see the same underlying issue herein when opening the contextmenu2 (resp. now contextmenu3) for the submenu “Grant access to”.
The failing result value at least is the same.  But why does it happen?
Does anybody has any idea?   
See the testcase (tree view) and also the screenshot/image attached.

d7_2_laz

  • Full Member
  • ***
  • Posts: 109
I elaborated the test case a bit so that it has windows shell context menu on treeview as well as on listview (attached).

- Select a txt file in the listview.
- Right mouse click. Position on "Open with ...".
  The candidates list is empty.  Why? In D7 it was populated and i don't know why this went lost now ....  resp.: why the HandleMenuMsg resp. HandleMenuMsg2 does not succeed.

ASerge

  • Hero Member
  • *****
  • Posts: 1778
It's a pity that five years ago I didn't check this for files, but only for directories. At first glance, I do not see an error, and it works in Delphi. I'll try to dig deeper into what the problem is, but not quickly.

d7_2_laz

  • Full Member
  • ***
  • Posts: 109
Hello ASerge,
thanks for attention!
I already noticed some things:
- in my (D7 working) version i don't use "FICM3" at all. Here it is solely around IContextMenu2 / FICM2.HandleMenuMsg
- Normally the call to FICM2.HandleMenuMsg is done conditionally, ie.
    if ((Msg = WM_INITMENUPOPUP) or (Msg = WM_DRAWITEM) or (Msg = WM_MENUCHAR) or (Msg = WM_MEASUREITEM)) and Assigned(FICM2) then  ..
- Unfortunately those messages are not passed here, so it's needed to ignore such condition for the moment.
- But as result: if the only condition is:  if Assigned(FICM2) …), then there are repeated calls to HandleMenuMsg with either wParam or lParam being zero   

Unfortunately i did not succeed yet to prepare a very little D7 mini demo where it is working.
So i need to dig myself too  For to isolate more precise within my app/D7 – with much other stuff around  - where exactly it's guaranteed to work. I do not see it yet.

About folders, but not files: as the folders do not have an "Open with .." command, it could not be recognized here ...  :-)  But for the folders i think it is the same if you look onto "Grant access for", eg. using the treeview.

ASerge

  • Hero Member
  • *****
  • Posts: 1778
It seems that Lazarus is not handling some messages correctly. I haven't found where yet, but I can offer workaround.
This is from a attached unit:
Code: Pascal  [Select][+][-]
  1. type
  2.   TShiftKeyState = (sksAutoDetect, sksNone, sksPressed);
  3.  
  4. // ForFileName can be a directory name
  5.  
  6. procedure ShowSystemPopup(const ForFileName: string; const InScreenPos: TPoint;
  7.   ShiftKeyState: TShiftKeyState = sksAutoDetect);

As a result, the menu call code becomes this:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.ShellListView1ContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean);
  2. var
  3.   FileName: string;
  4. begin
  5.   if ShellListView1.Selected = nil then
  6.     Exit;
  7.   FileName := ShellListView1.GetPathFromItem(ShellListView1.Selected);
  8.   ShowSystemPopup(FileName, ShellListView1.ClientToScreen(MousePos));
  9. end;

d7_2_laz

  • Full Member
  • ***
  • Posts: 109
Thank you Serge,
i'll check it directly after!
But before that i'd like to tell that i think i found it.

In fact the only thing that initially hindered in my Delphi small example the submenu to appear.
was, that the HandleMenuMsg was not bound to the condition:: do it only at WM_INITMENUPOPUP. (as already mentioned above).

By that it's too much garbage resp. other stuff  in either wParam or lParam and it's called a series of times with disrupting parameters.

Attached two test probs (D7 and Lazarus converted):
The Lazarus version won't work, obiously because WM_INITMENUPOPUP is not triggered.
I think that's you refer to when mentioning the handling of some messages.
If i should guess, i would guess: if you pass WM_INITMENUPOPUP then it should work.

d7_2_laz

  • Full Member
  • ***
  • Posts: 109
Hello ASerge,

tried the workaround and it does fine what he is expected to do. Folders within the listview are handled correctly too, ie- the submenu "Grant access to" for a folder does reappear. It's nice encapsulated to easy to use  :)
Probably it would not take much to make it work for the treeview too.

However i'd prefer to see the "traditional" way downward compatible work again, as there are needs to apply more stuff herein, namely to append to the system menu user defined items and functions (such customizing might be part of the ShowSystemPoupup coding though, but by that it won't be very generic any longer.

So for me it would be sufficient simply to know what's the future way to go.
Based on the workaround or will those messages triggered again later by Lazarus? What might be the decision?

For to have the full picture: this is the normal conditions embedding (i got it from a couple of readings years ago, so i don't remember each detail):

Code: Pascal  [Select][+][-]
  1.     if ((Msg = WM_INITMENUPOPUP) or (Msg = WM_DRAWITEM) or (Msg = WM_MENUCHAR)
  2.       or (Msg = WM_MEASUREITEM)) and Assigned(ICM2) then
  3.       begin
  4.         ICM2.HandleMenuMsg(Msg, wParam, lParam);
  5.         Result := 0;
  6.       end;

About the messages i thought about if there is any trick to pickup the right message form the message loop.
I noticed that (in my mini example):
in Delphi 7 there are 71 message invocations in the phase were ICM2 is assigned.
Within those, there is one single occurance where Message.Msg is WM_INITMENUPOPUP.
That is:
Code: Pascal  [Select][+][-]
  1. wParam  106825913  lparam: 0           === ICM2 is assigned here;    And Msg is WM_INITMENUPOPUP

In Lazarus there are *in total* only 3 messages where ICM2 is assigned. Those are:
Code: Pascal  [Select][+][-]
  1. wParam  7864940   lparam: 2            ===  ICM2 ist assigned here
  2. wParam  0         lparam: 22456144     ===  ICM2 ist assigned here
  3. wParam  0         lparam: 0            ===  ICM2 ist assigned here

Punctually calling HandleMenuMsg for each of them selectively does fail. Not much room to play.
Here are definitively messages missing that would be required for to meke the HandleMenuMsg work correctly.

What do you think is the right way to react?

 

TinyPortal © 2005-2018