Componentes.Terceros.jcl/official/2.1.1/source/vcl/JclOpenDialogHooks.pas
2010-01-18 16:51:36 +00:00

390 lines
14 KiB
ObjectPascal

{**************************************************************************************************}
{ }
{ Project JEDI Code Library (JCL) }
{ }
{ 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 OpenDlgFavAdapter.pas. }
{ }
{ The Initial Developer of the Original Code is Petr Vones. }
{ Portions created by Petr Vones are Copyright (C) Petr Vones. All rights reserved. }
{ }
{ Contributor(s): }
{ Salvatore Besso }
{ Florent Ouchet (move to JCL runtime) }
{ }
{**************************************************************************************************}
{ }
{ Last modified: $Date:: 2009-10-03 12:13:30 +0200 (sam., 03 oct. 2009) $ }
{ Revision: $Rev:: 3035 $ }
{ Author: $Author:: outchy $ }
{ }
{**************************************************************************************************}
unit JclOpenDialogHooks;
interface
{$I jcl.inc}
uses
Windows, Messages, Classes, SysUtils, Controls, StdCtrls, ExtCtrls,
{$IFDEF UNITVERSIONING}
JclUnitVersioning,
{$ENDIF UNITVERSIONING}
JclBase, JclPeImage, JclWin32;
type
TJclOpenDialogHook = class (TObject)
private
FDisableHelpButton: Boolean;
FDisablePlacesBar: Boolean;
FHooks: TJclPeMapImgHooks;
FIsOpenPictureDialog: Boolean;
FParentWndInstance: Pointer;
FOldParentWndInstance: Pointer;
FPictureDialogLastFolder: string;
FWndInstance: Pointer;
FOldWndInstance: Pointer;
FOnClose: TNotifyEvent;
FOnShow: TNotifyEvent;
function GetCurrentFolder: string;
function GetFileNameEditWnd: HWND;
procedure SetCurrentFolder(const Value: string);
protected
FHandle: HWND;
FParentWnd: HWND;
procedure AdjustControlPos; virtual;
procedure DialogFolderChange; virtual;
procedure DialogShow; virtual;
procedure DoClose;
procedure DoShow;
procedure ParentWndProc(var Message: TMessage); virtual;
procedure WndProc(var Message: TMessage); virtual;
property FileNameEditWnd: HWND read GetFileNameEditWnd;
public
constructor Create; virtual;
destructor Destroy; override;
procedure HookDialogs;
procedure UnhookDialogs;
property CurrentFolder: string read GetCurrentFolder write SetCurrentFolder;
property DisableHelpButton: Boolean read FDisableHelpButton write FDisableHelpButton;
property DisablePlacesBar: Boolean read FDisablePlacesBar write FDisablePlacesBar;
property IsOpenPictureDialog: Boolean read FIsOpenPictureDialog;
property PictureDialogLastFolder: string read FPictureDialogLastFolder write FPictureDialogLastFolder;
property OnClose: TNotifyEvent read FOnClose write FOnClose;
property OnShow: TNotifyEvent read FOnShow write FOnShow;
end;
TJclOpenDialogHookClass = class of TJclOpenDialogHook;
EJclOpenDialogHookError = class(EJclError);
function InitializeOpenDialogHook(OpenDialogHookClass: TJclOpenDialogHookClass): TJclOpenDialogHook;
procedure FinalizeOpenDialogHook;
{$IFDEF UNITVERSIONING}
const
UnitVersioning: TUnitVersionInfo = (
RCSfile: '$URL: https://jcl.svn.sourceforge.net/svnroot/jcl/tags/JCL-2.1-Build3536/jcl/source/vcl/JclOpenDialogHooks.pas $';
Revision: '$Revision: 3035 $';
Date: '$Date: 2009-10-03 12:13:30 +0200 (sam., 03 oct. 2009) $';
LogPath: 'JCL\source\vcl';
Extra: '';
Data: nil
);
{$ENDIF UNITVERSIONING}
implementation
uses
CommDlg, Dlgs,
JclFileUtils, JclStrings, JclSysInfo, JclSysUtils,
JclVclResources;
{$R JclOpenDialog.res}
const
OpenDialogTemplateName = 'JCLOPENDLGHOOK';
OpenPictureDialogTemplateName = 'DLGTEMPLATE';
type
TGetOpenFileName = function (var OpenFile: TOpenFilename): Bool; stdcall;
var
OldGetOpenFileName: TGetOpenFileName;
OldGetSaveFileName: TGetOpenFileName;
OldExplorerHook: function(Wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): UINT stdcall;
GlobalOpenDialogHook: TJclOpenDialogHook;
function NewExplorerHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
begin
Result := OldExplorerHook(Wnd, Msg, WParam, LParam);
if (Msg = WM_INITDIALOG) and Assigned(GlobalOpenDialogHook) then
begin
GlobalOpenDialogHook.FHandle := Wnd;
GlobalOpenDialogHook.FOldWndInstance := Pointer(SetWindowLongPtr(Wnd, GWLP_WNDPROC, LONG_PTR(GlobalOpenDialogHook.FWndInstance)));
CallWindowProc(GlobalOpenDialogHook.FWndInstance, Wnd, Msg, WParam, LParam);
end;
end;
procedure InitOpenFileStruct(var OpenFile: TOpenFilename);
var
InitDir: string;
begin
with OpenFile do
if Flags and OFN_EXPLORER <> 0 then
begin
if Assigned(GlobalOpenDialogHook) then
GlobalOpenDialogHook.FIsOpenPictureDialog := False;
if Flags and OFN_ENABLETEMPLATE = 0 then
begin
OldExplorerHook := lpfnHook;
lpfnHook := NewExplorerHook;
lpTemplateName := OpenDialogTemplateName;
hInstance := FindResourceHInstance(FindClassHInstance(GlobalOpenDialogHook.ClassType));
Flags := Flags or OFN_ENABLETEMPLATE;
if Assigned(GlobalOpenDialogHook) then
begin
if GlobalOpenDialogHook.DisableHelpButton then
Flags := Flags and (not OFN_SHOWHELP);
if GlobalOpenDialogHook.DisablePlacesBar and (lStructSize = SizeOf(TOpenFilename)) then
FlagsEx := FlagsEx or OFN_EX_NOPLACESBAR;
end;
end
else
if (StrIComp(lpTemplateName, OpenPictureDialogTemplateName) = 0) and Assigned(GlobalOpenDialogHook) then
begin
GlobalOpenDialogHook.FIsOpenPictureDialog := True;
OldExplorerHook := lpfnHook;
lpfnHook := NewExplorerHook;
InitDir := GlobalOpenDialogHook.PictureDialogLastFolder;
if DirectoryExists(InitDir) then
lpstrInitialDir := PChar(GlobalOpenDialogHook.PictureDialogLastFolder)
else
GlobalOpenDialogHook.PictureDialogLastFolder := '';
end;
end;
end;
function NewGetOpenFileName(var OpenFile: TOpenFilename): Bool; stdcall;
begin
InitOpenFileStruct(OpenFile);
Result := OldGetOpenFileName(OpenFile);
end;
function NewGetSaveFileName(var OpenFile: TOpenFilename): Bool; stdcall;
begin
InitOpenFileStruct(OpenFile);
Result := OldGetSaveFileName(OpenFile);
end;
function InitializeOpenDialogHook(OpenDialogHookClass: TJclOpenDialogHookClass): TJclOpenDialogHook;
begin
if Assigned(GlobalOpenDialogHook) then
begin
if GlobalOpenDialogHook.ClassType <> OpenDialogHookClass then
raise EJclOpenDialogHookError.CreateResFmt(@RsEOpenDialogHookExists, [GlobalOpenDialogHook.ClassName]);
end
else
GlobalOpenDialogHook := OpenDialogHookClass.Create;
Result := GlobalOpenDialogHook;
end;
procedure FinalizeOpenDialogHook;
begin
FreeAndNil(GlobalOpenDialogHook);
end;
//=== { TJclOpenDialogHook } =================================================
constructor TJclOpenDialogHook.Create;
begin
inherited Create;
FHooks := TJclPeMapImgHooks.Create;
FParentWndInstance := MakeObjectInstance(ParentWndProc);
FWndInstance := MakeObjectInstance(WndProc);
end;
destructor TJclOpenDialogHook.Destroy;
begin
UnhookDialogs;
FreeObjectInstance(FParentWndInstance);
FreeObjectInstance(FWndInstance);
FreeAndNil(FHooks);
inherited Destroy;
end;
procedure TJclOpenDialogHook.AdjustControlPos;
begin
// override to customize
end;
procedure TJclOpenDialogHook.DialogFolderChange;
begin
// override to customize
end;
procedure TJclOpenDialogHook.DialogShow;
begin
// override to customize
FParentWnd := GetParent(FHandle);
if IsWin2k or IsWinXP then
FOldParentWndInstance := Pointer(SetWindowLongPtr(FParentWnd, GWLP_WNDPROC, LONG_PTR(FParentWndInstance)));
DoShow;
end;
procedure TJclOpenDialogHook.DoClose;
begin
if Assigned(FOnClose) then
FOnClose(Self);
end;
procedure TJclOpenDialogHook.DoShow;
begin
if Assigned(FOnShow) then
FOnShow(Self);
end;
function TJclOpenDialogHook.GetCurrentFolder: string;
var
Path: array [0..MAX_PATH] of Char;
begin
SetString(Result, Path, SendMessage(FParentWnd, CDM_GETFOLDERPATH, SizeOf(Path), Integer(@Path)));
StrResetLength(Result);
end;
function TJclOpenDialogHook.GetFileNameEditWnd: HWND;
begin
Result := GetDlgItem(FParentWnd, edt1);
if Result = 0 then
Result := GetDlgItem(FParentWnd, cmb13);
end;
procedure TJclOpenDialogHook.HookDialogs;
procedure HookImportsForModule(ModuleBase: Pointer);
const
comdlg32 = 'comdlg32.dll';
begin
if ModuleBase <> nil then
begin
{$IFDEF UNICODE}
FHooks.HookImport(ModuleBase, comdlg32, 'GetOpenFileNameW', @NewGetOpenFileName, @OldGetOpenFileName);
FHooks.HookImport(ModuleBase, comdlg32, 'GetSaveFileNameW', @NewGetSaveFileName, @OldGetSaveFileName);
{$ELSE}
FHooks.HookImport(ModuleBase, comdlg32, 'GetOpenFileNameA', @NewGetOpenFileName, @OldGetOpenFileName);
FHooks.HookImport(ModuleBase, comdlg32, 'GetSaveFileNameA', @NewGetSaveFileName, @OldGetSaveFileName);
{$ENDIF UNICODE}
end;
end;
var
Pe: TJclPeImage;
I: Integer;
HookedModule: LongWord;
begin
{ TODO : Hook all loaded modules }
Pe := TJclPeImage.Create(True);
try
HookedModule := FindClassHInstance(ClassType);
Pe.AttachLoadedModule(HookedModule);
if Pe.StatusOK then
begin
HookImportsForModule(Pointer(HookedModule));
for I := 0 to Pe.ImportList.UniqueLibItemCount - 1 do
HookImportsForModule(Pointer(GetModuleHandle(PChar(Pe.ImportList.UniqueLibItems[I].FileName))));
end;
finally
Pe.Free;
end;
end;
procedure TJclOpenDialogHook.ParentWndProc(var Message: TMessage);
begin
with Message do
begin
Result := CallWindowProc(FOldParentWndInstance, FParentWnd, Msg, WParam, LParam);
if Msg = WM_SIZE then
AdjustControlPos;
end;
end;
procedure TJclOpenDialogHook.SetCurrentFolder(const Value: string);
var
LastFocus: HWND;
FileNameBuffer: string;
begin
if (FParentWnd <> 0) and DirectoryExists(Value) then
begin
LastFocus := GetFocus;
FileNameBuffer := GetWindowCaption(FileNameEditWnd);
SendMessage(FParentWnd, CDM_SETCONTROLTEXT, edt1, LPARAM(PChar(Value)));
SendMessage(GetDlgItem(FParentWnd, 1), BM_CLICK, 0, 0);
SendMessage(FParentWnd, CDM_SETCONTROLTEXT, edt1, LPARAM(PChar(FileNameBuffer)));
SetFocus(LastFocus);
end;
end;
procedure TJclOpenDialogHook.UnhookDialogs;
var
I: Integer;
begin
I := 0;
while I < FHooks.Count do
if not FHooks[I].Unhook then
Inc(I);
end;
procedure TJclOpenDialogHook.WndProc(var Message: TMessage);
procedure Default;
begin
with Message do
Result := CallWindowProc(FOldWndInstance, FHandle, Msg, WParam, LParam);
end;
begin
if FHandle <> 0 then
begin
case Message.Msg of
WM_NOTIFY:
begin
case (POFNotify(Message.LParam)^.hdr.code) of
CDN_INITDONE:
DialogShow;
CDN_FOLDERCHANGE:
if not IsOpenPictureDialog then
DialogFolderChange;
CDN_FILEOK:
if IsOpenPictureDialog then
FPictureDialogLastFolder := CurrentFolder;
end;
Default;
end;
WM_NCDESTROY:
begin
Default;
FHandle := 0;
end;
else
Default;
end;
end;
end;
{$IFDEF UNITVERSIONING}
initialization
RegisterUnitVersion(HInstance, UnitVersioning);
finalization
UnregisterUnitVersion(HInstance);
{$ENDIF UNITVERSIONING}
end.