Author: Jonas Bilinkevicius
Using the TOpenDialog and TSaveDialog components you get the standard Windows
dialog boxes including the ability to create/ delete files or folders. Is it
possible to block the create/ delete options?
Answer:
Well, few things are really impossible if you try hard enough, but this is at least
somewhat difficult. The common dialog API has no facility to do this, the dialogs
simply use the same listview class Explorer also uses, so it has all the same
functionality. So to block these functions one would have to subclass (the API way)
the listview control (to block right mouse clicks and the offending keyboard
messages as well as WM_CONTEXTMENU). One could do that in the dialogs OnShow event.
The problem is finding the handle of the listview, these Explorer-style dialogs
have an utterly weird internal window hierarchy. And the listview in question has
not been created yet when the OnShow event fires (go figure). So you have to post a
user message to the form from the OnShow event and do the subclassing in that
messages handler.
Here is a quick sketch of a modified opendialog class that prevents the use of the
listviews popup menu. For some reason it is not possible to trap the DEL key press
on the listview level, so if you want to also trap that, and perhaps even the
editing of filenames, you will also need to subclass the shellview, which is the
parent of the listview, and look for WM_NOTIFY messages from the listview there.
1 { ...}
2 type
3 TSafeOpenDialog = class(Dialogs.TOpenDialog)
4 private
5 FOldListviewProc: Pointer;
6 FListviewMethodInstance: Pointer;
7 FLIstview: HWND;
8 procedure WMApp(var msg: TMessage); message WM_APP;
9 protected
10 procedure DoShow; override;
11 procedure ListviewWndProc(var msg: TMessage);
12 public
13 destructor Destroy; override;
14 end;
15
16 destructor TSafeOpenDialog.Destroy;
17 begin
18 inherited;
19 if Assigned(FListviewMethodInstance) then
20 FreeObjectInstance(FListviewMethodInstance);
21 end;
22
23 procedure TSafeOpenDialog.DoShow;
24 begin
25 inherited;
26 PostMessage(handle, WM_APP, 0, 0);
27 end;
28
29 procedure TSafeOpenDialog.ListviewWndProc(var msg: TMessage);
30 begin
31 msg.result := 0;
32 case msg.Msg of
33 WM_RBUTTONDOWN, WM_RBUTTONUP, WM_CONTEXTMENU:
34 Exit;
35 end;
36 msg.result := CallWindowProc(FOldListviewProc, FLIstview, msg.Msg,
37 msg.WParam, msg.LParam);
38 end;
39
40 procedure TSafeOpenDialog.WMApp(var msg: TMEssage);
41 begin
42 FListviewMethodInstance := MakeObjectInstance(ListviewWndProc);
43 FListview := FindWindowEx(Windows.GetParent(handle), 0, 'SHELLDLL_DefView', nil);
44 if FListview <> 0 then
45 begin
46 FListview := GetWindow(FListview, GW_CHILD);
47 if FListview <> 0 then
48 FOldListviewProc := Pointer(SetWindowLong(FListview, GWL_WNDPROC,
49 Integer(FListviewMethodInstance)))
50 else
51 OutputDebugString('Listview not found');
52 end
53 else
54 OutputDebugString('Shell view not found');
55 end;
|