-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathConEditPlus.ShellContextMenuHelper.pas
More file actions
177 lines (163 loc) · 5.67 KB
/
ConEditPlus.ShellContextMenuHelper.pas
File metadata and controls
177 lines (163 loc) · 5.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//
unit ConEditPlus.ShellContextMenuHelper;
interface
uses
Winapi.Windows, Winapi.ShlObj, Winapi.ShellAPI, Winapi.ActiveX, System.SysUtils, System.Classes,
System.Win.ComObj;
type
TShellContextMenu = class (TObject)
private
FContextMenu: IContextMenu;
FContextMenu2: IContextMenu2;
FContextMenu3: IContextMenu3;
FWndProcOld: Pointer;
FPopupWnd: HWND;
FOwnerWnd: HWND;
procedure HookWndProc();
procedure UnhookWndProc();
class function PopupWndProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; static;
procedure PrepareInterfaces();
public
constructor Create();
destructor Destroy(); override;
function ShowContextMenu(const FileName: string; OwnerWnd: HWND; const ScreenPt: TPoint): Boolean;
end;
implementation
{TShellContextMenu}
constructor TShellContextMenu.Create();
begin
inherited Create();
FContextMenu := nil;
FContextMenu2 := nil;
FContextMenu3 := nil;
FWndProcOld := nil;
FPopupWnd := 0;
FOwnerWnd := 0;
end;
destructor TShellContextMenu.Destroy();
begin
UnhookWndProc();
inherited;
end;
// Çàìåíà îêîííîé ïðîöåäóðû âðåìåííîãî îêíà äëÿ ëîâëè ñîîáùåíèé âëîæåííûõ Shell-ìåíþ
class function TShellContextMenu.PopupWndProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
var
SelfObj: TShellContextMenu;
res: LRESULT;
begin
// Ïîëó÷àåì îáúåêò TShellContextMenu ïî GWLP_USERDATA
SelfObj := TShellContextMenu(GetWindowLongPtr(hWnd, GWLP_USERDATA));
if Assigned(SelfObj) then
begin
// IContextMenu3 — ñàìûé íîâûé
if Assigned(SelfObj.FContextMenu3) then
begin
if SelfObj.FContextMenu3.HandleMenuMsg2(uMsg, wParam, lParam, res) = S_OK then
begin
Result := res;
Exit();
end;
end
// IContextMenu2 — ÷óòü ñòàðåå
else if Assigned(SelfObj.FContextMenu2) then
begin
if SelfObj.FContextMenu2.HandleMenuMsg(uMsg, wParam, lParam) = S_OK then
begin
Result := 0;
Exit();
end;
end;
// Îñòàëüíûå ñîîáùåíèÿ — ñòàíäàðòíàÿ îáðàáîòêà
if Assigned(SelfObj.FWndProcOld) then
begin
Result := CallWindowProc(SelfObj.FWndProcOld, hWnd, uMsg, wParam, lParam);
Exit();
end;
end;
Result := DefWindowProc(hWnd, uMsg, wParam, lParam);
end;
procedure TShellContextMenu.HookWndProc(); // Ïåðåíàçíà÷àåì îêîííóþ ïðîöåäóðó è ñîõðàíÿåì ñòàðóþ
begin
SetWindowLongPtr(FPopupWnd, GWLP_USERDATA, NativeInt(Self));
FWndProcOld := Pointer(SetWindowLongPtr(FPopupWnd, GWLP_WNDPROC, NativeInt(@TShellContextMenu.PopupWndProc)));
end;
procedure TShellContextMenu.UnhookWndProc(); // Âîññòàíàâëèâàåì îêîííóþ ïðîöåäóðó (î÷èùàåì hook)
begin
if FPopupWnd <> 0 then
begin
if Assigned(FWndProcOld) then
SetWindowLongPtr(FPopupWnd, GWLP_WNDPROC, NativeInt(FWndProcOld));
SetWindowLongPtr(FPopupWnd, GWLP_USERDATA, 0);
DestroyWindow(FPopupWnd);
FPopupWnd := 0;
end;
FWndProcOld := nil;
end;
procedure TShellContextMenu.PrepareInterfaces();
begin
FContextMenu2 := nil;
FContextMenu3 := nil;
if Assigned(FContextMenu) then
begin
Supports(FContextMenu, IContextMenu3, FContextMenu3);
if not Assigned(FContextMenu3) then
Supports(FContextMenu, IContextMenu2, FContextMenu2);
end;
end;
function TShellContextMenu.ShowContextMenu(const FileName: string; OwnerWnd: HWND; const ScreenPt: TPoint): Boolean;
var
pidl, child: PItemIDList;
sfgao: ULONG;
parentFolder: IShellFolder;
h_Menu: HMENU;
cmd: UINT;
ici: TCMInvokeCommandInfo;
begin
Result := False;
FOwnerWnd := OwnerWnd;
OleCheck(OleInitialize(nil));
try
FContextMenu := nil;
pidl := nil;
OleCheck(SHParseDisplayName(PChar(FileName), nil, pidl, 0, sfgao));
try
OleCheck(SHBindToParent(pidl, IID_IShellFolder, Pointer(parentFolder), child));
OleCheck(parentFolder.GetUIObjectOf(0, 1, child, IID_IContextMenu, nil, FContextMenu));
PrepareInterfaces();
// Âðåìåííîå îêíî äëÿ îáðàáîòêè ñîîáùåíèé âëîæåííûõ ìåíþ
FPopupWnd := CreateWindow('STATIC', nil, WS_POPUP, 0, 0, 0, 0, 0, 0, HInstance, nil);
if FPopupWnd = 0 then RaiseLastOSError();
HookWndProc();
try
h_Menu := CreatePopupMenu;
try
OleCheck(FContextMenu.QueryContextMenu(h_Menu, 0, 1, $7FFF, CMF_NORMAL));
cmd := UINT(TrackPopupMenu(
h_Menu,
TPM_RETURNCMD or TPM_LEFTALIGN or TPM_TOPALIGN,
ScreenPt.X, ScreenPt.Y, 0, FPopupWnd, nil
));
if cmd <> 0 then
begin
ZeroMemory(@ici, SizeOf(ici));
ici.cbSize := SizeOf(ici);
ici.hwnd := OwnerWnd;
ici.lpVerb := PAnsiChar(NativeUInt(cmd - 1));
ici.nShow := SW_SHOWNORMAL;
OleCheck(FContextMenu.InvokeCommand(ici));
Result := True;
end;
finally
DestroyMenu(h_Menu);
end;
finally
UnhookWndProc();
end;
finally
CoTaskMemFree(pidl);
end;
finally
OleUninitialize();
end;
end;
end.