Menu

[r2]: / trunk / Src / UOpenDialogEx.pas  Maximize  Restore  History

Download this file

277 lines (244 with data), 9.7 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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
{
* UOpenDialogEx.pas
*
* Implements an open dialog box subclass that aligns itself over its owner and
* works correctly with the Vista task bar. Dialog also supports help keywords.
*
* v1.0 of 10 Aug 2008 - Original version.
*
*
* ***** BEGIN LICENSE BLOCK *****
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Original Code is UOpenDialogEx.pas
*
* The Initial Developer of the Original Code is Peter Johnson
* (http://www.delphidabbler.com/).
*
* Portions created by the Initial Developer are Copyright (C) 2008 Peter
* Johnson. All Rights Reserved.
*
* Contributor(s): None
*
* ***** END LICENSE BLOCK *****
}
unit UOpenDialogEx;
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CAST OFF}
{$WARN UNSAFE_CODE OFF}
interface
uses
// Delphi
Dialogs, Messages, Windows;
type
{
TOpenDialogEx:
Subclasses the Open dialog box to enable the dialog to align itself over its
owner and to work correctly with the Vista task bar. Also adds support for
help keywords and help button.
}
TOpenDialogEx = class(TOpenDialog)
private
fHelpKeyword: string;
{Value of HelpKeyword property}
protected
fOldExplorerHook: Pointer;
{Reference to original explorer hook function provided by Delphi}
function TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool;
override;
{Overridden method that updates the DialogData structure to route message
processing through a custom explorer hook function while storing the
original explorer hook function for later use.
@param DialogFunc [in] Windows function to be called to execute dialog
box (GetOpenFileName() in this case).
@param DialogData [in] Data describing dialog box to be passed to
DialogFunc (in this case of type TOpenFileName).
}
function MessageHook(var Msg: TMessage): Boolean; override;
{Intercepts messages sent to the dialog window before the dialog’s window
procedure. This implementation changes default support for the help button
to include the new HelpKeyword property and to use the program's own help
manager.
@param Msg [in/out] Specifies message. Unchanged by this method. May be
modified by inherited implementation(s).
}
procedure DoShow; override;
{Sets up dialog just before it is displayed.
}
procedure AlignDlg; virtual;
{Aligns dialog box to owner control.
}
function DisplayHelp: Boolean; virtual;
{Calls program's help manager to display help if HelpKeyword or
HelpContext properties are set. HelpKeyword is used in preference.
@return True if help manager was called or False if not (i.e. neither
HelpKeyword nor HelpContext were set).
}
public
function Execute: Boolean; override;
{Displays dialog box. Esnures help button is displayed if HelpKeyword or
HelpContext properties are set.
@return True if user OKs and False if cancels.
}
published
property HelpKeyword: string
read fHelpKeyword write fHelpKeyword;
{ALink help keyword used to access help topic when help button clicked.
When set this property is used in preference to HelpContext}
end;
implementation
uses
// Delphi
Controls, CommDlg,
// Project
UDlgHelper, UHelpMgr;
var
HelpMsgID: DWORD = 0; // ID of dialog box help message
function NewExplorerHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM;
LParam: LPARAM): UINT; stdcall;
{Replacement explorer hook function called by Windows to process dialog box
messages. Original hook handles only WM_INITDIALOG message and CDN_INITDONE
notification. This replacement passes WM_INITDIALOG messages to original
hook but handles CDN_INITDONE to align the dialog box (original hook centres
it). All other messages are passed to original hook.
@param Wnd [in] Window handle of dialog box.
@param Msg [in] Identifies message being passed to hook.
@param WParam [in] Message parameter. Usage depends on message.
@param LParam [in] Message parameter. Usage depends on message.
@return Message specific return value.
}
//----------------------------------------------------------------------------
function OFNToDlg(const OFN: TOpenFilename): TOpenDialogEx;
{Gets reference to open dialog from custom data in open dialog data
structure.
@param OFN [in] Structure containing reference to dialog box object.
@return Required dialog box reference.
}
begin
Result := TOpenDialogEx(OFN.lCustData);
end;
function CallHookFn(const HookFn: Pointer): UINT;
{Calls explorer hook function with parameters passed to outer method.
@param HookFn [in] Pointer to hook function to be called.
@return Return value from called hook function.
}
type
// Hook function prototype
THookFn = function(Wnd: HWnd; Msg: UINT; WParam: Integer;
LParam: Integer): UINT; stdcall;
begin
Result := THookFn(HookFn)(Wnd, Msg, WParam, LParam);
end;
//----------------------------------------------------------------------------
var
Dlg: TOpenDialogEx; // reference to dialog box object
begin
// Set default result passed back to windows
Result := 0;
if Msg = WM_INITDIALOG then
// Dialog initialising: pass on to original hook function
Result := CallHookFn(OFNToDlg(POpenFileName(LParam)^).fOldExplorerHook)
else if Msg = WM_NOTIFY then
begin
// Get reference to dialog box object from data structure
Dlg := OFNToDlg(POFNotify(LParam)^.lpOFN^);
if POFNotify(LParam)^.hdr.code = CDN_INITDONE then
// Dialog intialization complete: align the dialog box. We don't call old
// hook function since all this does is centre the dialog box!
// Windows ignores return value (we leave as default 0)
Dlg.AlignDlg
else
// Other notification: pass on to original hook function
Result := CallHookFn(Dlg.fOldExplorerHook);
end;
end;
{ TOpenDialogEx }
procedure TOpenDialogEx.AlignDlg;
{Aligns dialog box to owner control.
}
begin
TDlgAligner.AlignToOwner(Self);
end;
function TOpenDialogEx.DisplayHelp: Boolean;
{Calls program's help manager to display help if HelpKeyword or HelpContext
properties are set. HelpKeyword is used in preference.
@return True if help manager was called or False if not (i.e. neither
HelpKeyword nor HelpContext were set).
}
begin
Result := True;
if HelpKeyword <> '' then
HelpMgr.ShowHelp(HelpKeyword)
else if HelpContext <> 0 then
HelpMgr.ShowHelp(HelpContext)
else
Result := False;
end;
procedure TOpenDialogEx.DoShow;
{Sets up dialog just before it is displayed.
}
begin
// Prevent task bar button press bringing owner window to foreground
TDlgHelper.SetDlgParentToOwner(Self);
inherited;
end;
function TOpenDialogEx.Execute: Boolean;
{Displays dialog box. Esnures help button is displayed if HelpKeyword or
HelpContext properties are set.
@return True if user OKs and False if cancels.
}
begin
if (fHelpKeyword <> '') or (HelpContext <> 0) then
Options := Options + [ofShowHelp];
Result := inherited Execute;
end;
function TOpenDialogEx.MessageHook(var Msg: TMessage): Boolean;
{Intercepts messages sent to the dialog window before the dialog’s window
procedure. This implementation changes default support for the help button
to include the new HelpKeyword property and to use the program's own help
manager.
@param Msg [in/out] Specifies message. Unchanged by this method. May be
modified by inherited implementation(s).
}
begin
if Msg.Msg = HelpMsgID then
Result := DisplayHelp
else
Result := inherited MessageHook(Msg);
end;
function TOpenDialogEx.TaskModalDialog(DialogFunc: Pointer;
var DialogData): Bool;
{Overridden method that updates the DialogData structure to route message
processing through a custom explorer hook function while storing the original
explorer hook function for later use.
@param DialogFunc [in] Windows function to be called to execute dialog box
(GetOpenFileName() in this case).
@param DialogData [in] Data describing dialog box to be passed to DialogFunc
(in this case of type TOpenFileName).
}
begin
if NewStyleControls and not (ofOldStyleDialog in Options) then
begin
// Record previous explorer hook function for later use
fOldExplorerHook := @TOpenFileName(DialogData).lpfnHook;
// Store reference to our new explorer hook function in DialogData
TOpenFileName(DialogData).lpfnHook := NewExplorerHook;
// Store reference to this object in DialogData
TOpenFileName(DialogData).lCustData := Integer(Self);
end;
// Call inherited function with (modified) data structure
Result := inherited TaskModalDialog(DialogFunc, DialogData);
end;
initialization
// Get ID of common dialog help message
HelpMsgID := RegisterWindowMessage(CommDlg.HELPMSGSTRING);
end.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.