GetSaveFileName завершается ошибкой с CDERR_FINDRESFAILURE

0

Я написал компонент TOpenPictDialog (исходный код, см. Ниже), который, наконец, терпит неудачу при определенных обстоятельствах при вызове

Результат: = TDialogFunc (DialogFunc) (DialogData);

в Dialogs.pas. Поскольку DialogFunc правильно указывает на GetOpenFileName, я вызываю CommDlgExtendedError после этого, чтобы проверить, что случилось. Он возвращает CDERR_FINDRESFAILURE. В этом случае диалог просто не отображается. Моя тестовая форма содержит только кнопку и компонент TOpenPictDialog, при нажатии кнопки OpenPictDialog1-> Вызывается вызов - все.

Очень странно, что он отлично работает (кроме того, что TListView мерцает при изменении размера) при одном из следующих обстоятельств:

a) добавить ExtDlgs в "uses" в форме вызова; b) добавить оригинал TOpenPictureDialog в форму без вызова; c) добавить в проект файл PAS, содержащий TOpenPictDialog (хотя TOpenPictDialog уже установлен)

Если я пишу приложение C++ Builder с одной формой вызова, я никогда не получаю работу TOpenPictDialog (даже если я добавлю дополнительный компонент TOpenPictureDialog).

unit PictureDlg;

{$R-,H+,X+}

{$IF CompilerVersion > 23} {$DEFINE GE_DXE2} {$IFEND}

interface

{$IFDEF GE_DXE2}
   uses Winapi.Messages, Winapi.Windows, System.SysUtils, System.Classes, Vcl.Controls, Vcl.StdCtrls,
     Vcl.Graphics, Vcl.ExtCtrls, Vcl.Buttons, Vcl.Dialogs, Vcl.ExtDlgs, Vcl.Consts, Vcl.ComCtrls;
{$ELSE}
   uses Messages, Windows, SysUtils, Classes, Controls, StdCtrls,
     Graphics, ExtCtrls, Buttons, Dialogs, ExtDlgs, Consts, ComCtrls;
{$ENDIF}

(*$HPPEMIT '// Alias records for C++ code that cannot compile in STRICT mode yet.' *)
(*$HPPEMIT '#if defined(_VCL_ALIAS_RECORDS)' *)
(*$HPPEMIT '#if !defined(STRICT)' *)
// (*$HPPEMIT '  #pragma alias "@Vcl@Extdlgs@TOpenPictDialog@Execute$qqrpv"="@Vcl@Extdlgs@TOpenPictDialog@Execute$qqrp6HWND__"' *)
(*$HPPEMIT '#endif' *)
(*$HPPEMIT '#endif' *)

type

{ TOpenPictDialog }

  TOpenPictDialog = class(TOpenDialog)
  private
    FListView: TListView;
    FTopLabel, FBottomLabel: TStaticText;
    FImageCtrl: TImage;
    FSavedFilename: string;
    FOldDialogWndProc: Pointer;
    FDialogMethodInstance: Pointer;
    FDialogHandle: THandle;
    function  IsFilterStored: Boolean;
    procedure DialogWndProc(var Msg: TMessage);
  protected
    procedure DoClose; override;
    procedure DoSelectionChange; override;
    procedure DoShow; override;
    function TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool; override;
  published
    property Filter stored IsFilterStored;
  public
    constructor Create(AOwner: TComponent); override;
    function Execute(ParentWnd: HWND): Boolean; override;
    property DialogListView: TListView read FListView;
    property DialogImage: TImage read FImageCtrl;
    property TopLabel: TStaticText read FTopLabel;
    property BottomLabel: TStaticText read FBottomLabel;
  end;

procedure Register;

implementation

uses 
{$IFDEF GE_DXE2}
{$IF DEFINED(CLR)}
  System.Runtime.InteropServices, System.Reflection, System.Security.Permissions, System.IO,
{$IFEND}
  System.Math, Vcl.Forms, Winapi.CommDlg, Winapi.Dlgs, System.Types, Winapi.ShlObj, Winapi.ActiveX;
{$ELSE}
{$IF DEFINED(CLR)}
  InteropServices, Reflection, Permissions, IO,
{$IFEND}
  Math, Forms, CommDlg, Dlgs, Types, ShlObj, ActiveX;
{$ENDIF}

{ TOpenPictDialog }

constructor TOpenPictDialog.Create(AOwner: TComponent);
begin
  FDialogHandle := 0;
  FDialogMethodInstance := NIL;

  inherited Create(AOwner);
  Filter := GraphicFilter(TGraphic);

  FListView := TListView.Create(Self);
  FImageCtrl := TImage.Create(Self);

  with FListView do
  begin
    Name := 'ListView';
    SetBounds(204, 5, 169, 200);
    BevelOuter := bvNone;
    BorderWidth := 6;
    TabOrder := 1;
    Color := clWindow;
    ParentDoubleBuffered := false;
    DoubleBuffered := true;
    OwnerDraw := true;
    Ctl3D := true;

    with FImageCtrl do
    begin
       Picture := nil;
       Name := 'Image';
       Parent := FListView;
    end;
  end;

  FTopLabel := TStaticText.Create(Self);
  with FTopLabel do
  begin
   Name := 'TopLabel';
   SetBounds(6, 6, 157, 23);
   AutoSize := False;
   Caption := 'Preview:';
  end;

  FBottomLabel := TStaticText.Create(Self);
  with FBottomLabel do
  begin
   Name := 'BottomLabel';
   SetBounds(6, 6, 157, 23);
   AutoSize := False;
   Caption := 'Image size: 208 x 149 px';
   Alignment := taCenter;
  end;
end;

procedure TOpenPictDialog.DialogWndProc(var Msg: TMessage);
var
  PreviewRect, ListViewRect, WindowRect, LabelRect: TRect;
  WndControl: HWND;

begin
    Msg.Result := CallWindowProc(FOldDialogWndProc, FDialogHandle, Msg.Msg, Msg.WParam, Msg.LParam);

    if ((Msg.Msg = WM_WINDOWPOSCHANGED) and
            ((TWMWindowPosMsg(Msg).WindowPos.Flags and SWP_NOSIZE) = 0)) or
            (Msg.Msg = WM_SHOWWINDOW) then begin

        PreviewRect := FListView.BoundsRect;

        GetWindowRect(Handle, WindowRect);

        WndControl := FindWindowEx(FDialogHandle, 0, 'SHELLDLL_DefView', nil);
        WndControl := FindWindowEx(WndControl, 0, 'SysListView32', nil);

        if WndControl <> 0 then begin
            GetWindowRect(WndControl, ListViewRect);
            PreviewRect.Top := ListViewRect.Top - WindowRect.Top;
            PreviewRect.Bottom := PreviewRect.Top + ListViewRect.Bottom - ListViewRect.Top;

           if (not EqualRect(PreviewRect, FListView.BoundsRect)) then
              FListView.BoundsRect := PreviewRect;

            LabelRect := PreviewRect;
            Dec(LabelRect.Top, 24);
            LabelRect.Bottom := LabelRect.Top + 16;

            FTopLabel.BoundsRect := LabelRect;

            LabelRect := PreviewRect;
            LabelRect.Top := PreviewRect.Bottom + 9;
            LabelRect.Bottom := LabelRect.Top + 16;

            FBottomLabel.BoundsRect := LabelRect;
        end;
    end;
end;

procedure TOpenPictDialog.DoSelectionChange;
var
  FullName: string;

  function ValidFile(const FileName: string): Boolean;
  begin
    Result := FileGetAttr(FileName) <> -1;
  end;

begin
  FullName := FileName;
  if FullName <> FSavedFilename then
  begin
    FSavedFilename := FullName;
  end;
  inherited DoSelectionChange;
end;

procedure TOpenPictDialog.DoClose;
begin
  if Assigned(FDialogMethodInstance) then begin
    SetWindowLong(FDialogHandle, GWL_WNDPROC, Integer(FOldDialogWndProc));
    FreeObjectInstance(FDialogMethodInstance);
  end;

  FDialogHandle := 0;
  FDialogMethodInstance := NIL;

  inherited DoClose;
  { Hide any hint windows left behind }
  Application.HideHint;
end;

procedure TOpenPictDialog.DoShow;
var
  PreviewRect, StaticRect, OldDialogRect: TRect;
  DialogWidth, DialogHeight, NewLeft, NewTop: integer;
const
  SizeIncrease = 25;
begin
  FDialogHandle := GetParent(Handle);
  GetWindowRect(FDialogHandle, OldDialogRect);
  DialogWidth := OldDialogRect.Right - OldDialogRect.Left + SizeIncrease;
  DialogHeight := OldDialogRect.Bottom - OldDialogRect.Top;
  NewLeft := (Screen.Width - DialogWidth) div 2;
  NewTop := (Screen.Height - DialogHeight) div 2;

  GetWindowRect(Handle, PreviewRect);

  MoveWindow(FDialogHandle, NewLeft, NewTop, DialogWidth, DialogHeight, true);
  MoveWindow(Handle, 0, 0, PreviewRect.Right - PreviewRect.Left + SizeIncrease, PreviewRect.Bottom - PreviewRect.Top, false);

  StaticRect := GetStaticRect;
  GetClientRect(Handle, PreviewRect);
  PreviewRect.Left := StaticRect.Left + (StaticRect.Right - StaticRect.Left);
  Inc(PreviewRect.Top, 4);
  Dec(PreviewRect.Right, 8);
  Dec(PreviewRect.Bottom, 20);
  FListView.BoundsRect := PreviewRect;

  FDialogMethodInstance := MakeObjectInstance(DialogWndProc);
  FOldDialogWndProc := Pointer(SetWindowLong(FDialogHandle, GWL_WNDPROC, Integer(FDialogMethodInstance)));

  FSavedFilename := '';
  FListView.ParentWindow := Handle;
  FTopLabel.ParentWindow := Handle;
  FBottomLabel.ParentWindow := Handle;

  inherited DoShow;
end;

[UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.SafeSubWindows)]
function TOpenPictDialog.Execute(ParentWnd: HWND): Boolean;
begin
  if NewStyleControls and not (ofOldStyleDialog in Options) and not
     ((Win32MajorVersion >= 6) and UseLatestCommonDialogs) then
    Template := 'DLGTEMPLATE'
  else
{$IF DEFINED(CLR)}
    Template := '';
{$ELSE}
    Template := nil;
{$IFEND}
  Result := inherited Execute(ParentWnd);
end;

function TOpenPictDialog.TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool;
begin
  // This makes sense ONLY if you are compiling with a run-time packages
  // Thanks to Peter Below (www.delphifaq.com)
  TOpenfilename(Dialogdata).hInstance := FindClassHInstance(Classtype);
  Result := inherited TaskModalDialog(DialogFunc, DialogData);
end;

function TOpenPictDialog.IsFilterStored: Boolean;
begin
  Result := not (Filter = GraphicFilter(TGraphic));
end;

procedure Register;
begin
  RegisterComponents('Dialogs', [TOpenPictDialog]);
end;

end.
  • 0
    Обрежьте код. Поскольку вы даже не можете создать диалог, большая часть этого кода, вероятно, не имеет значения, поэтому не публикуйте его. Удалите все, что не способствует ошибке.
Теги:
getopenfilename

1 ответ

1

Когда вы скопировали код из ExtDlgs.pas, чтобы начать писать свои, вы не скопировали достаточно. В частности, вы не скопировали директиву $R которая связывает связанный с ней файл ExtDlgs.rc, который содержит ресурс диалога, описывающий дополнительную компоновку настраиваемого диалогового окна.

Ваш код сообщает API использовать ресурс диалога с именем DLGTEMPLATE, но вы не включили этот ресурс в свою программу. Это объясняет, почему код ошибки, который вы получаете, касается отказа найти ресурс. Использование модуля ExtDlgs имеет побочный эффект связывания ресурсов, связанных с этим устройством.

Перейти скопировать шаблон диалога из ExtDlgs.rc в свой собственный файл RC и связать его как ExtDlgs.pas. Однако используйте другое имя для ресурса, чтобы избежать столкновения имени с существующим ресурсом DLGTEMPLATE. Откорректируйте свой код соответствующим образом.

  • 0
    Спасибо Роб, что решил проблему!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню