如何在使用Melander的DragDrop套件时允许异常

时间:2012-04-28 19:53:52

标签: delphi exception drag-and-drop

我正在尝试Melander DragDrop套件的TDropFileTarget组件。目标是在拖放文件后执行某些任务。此外,如果在处理过程中出现问题,我希望收到例外情况。

似乎吞下了OnDrop事件处理程序中引发的异常。但是,即使我将raise语句放入组件的源代码中,我仍然无法收到异常。你能帮忙发表评论吗?

示例dfm文件。

    object Form4: TForm4
      Left = 0
      Top = 0
      Caption = 'Form4'
      ClientHeight = 270
      ClientWidth = 392
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'Tahoma'
      Font.Style = []
      OldCreateOrder = False
      PixelsPerInch = 96
      TextHeight = 13
      object edt1: TEdit
        Left = 56
        Top = 72
        Width = 257
        Height = 21
        TabOrder = 0
        Text = 'edt1'
      end
      object dropfiletarget2: TDropFileTarget
        DragTypes = [dtCopy, dtLink]
        OnDrop = dropfiletarget2Drop
        Target = edt1
        OptimizedMove = True
        Left = 56
        Top = 120
      end
    end

样本文件。

    unit Unit4;

    interface

    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, DragDrop, DropTarget, DragDropFile, StdCtrls;

    type
      TForm4 = class(TForm)
        edt1: TEdit;
        dropfiletarget2: TDropFileTarget;
        procedure dropfiletarget2Drop(Sender: TObject; ShiftState: TShiftState; APoint:
            TPoint; var Effect: Integer);
      private
        { Private declarations }
      public
        { Public declarations }
      end;

    var
      Form4: TForm4;

    implementation

    {$R *.dfm}

    procedure TForm4.dropfiletarget2Drop(Sender: TObject; ShiftState: TShiftState;
        APoint: TPoint; var Effect: Integer);
    begin
      raise Exception.Create('Error Message');
    end;

    end.

TCustomDropTarget.Drop

的原始代码
    function TCustomDropTarget.Drop(const dataObj: IDataObject; grfKeyState: Longint;
      pt: TPoint; var dwEffect: Longint): HResult;
    var
      ShiftState: TShiftState;
      ClientPt: TPoint;
    begin
      FScrollTimer.Enabled := False;

      // Protect resources against exceptions in OnDrop event handler.
      try
        // Refuse drop if we have lost the data object somehow.
        // This can happen if the drop is rejected in one of the other IDropTarget
        // methods (e.g. DragOver).
        if (not Enabled) or (FDataObject = nil) then
        begin
          dwEffect := DROPEFFECT_NONE;
          Result := E_UNEXPECTED;
        end else
        begin

          ShiftState := KeysToShiftStatePlus(grfKeyState);

          // Create a default drop effect based on the shift state and allowed
          // drop effects (or an OnGetDropEffect event if implemented).
          if (FTarget <> nil) then
            ClientPt := FTarget.ScreenToClient(pt)
          else
            ClientPt := pt;
          dwEffect := GetValidDropEffect(ShiftState, ClientPt, dwEffect);

          // Get data from source and generate an OnDrop event unless we failed to
          // get data.
          try
            if (FGetDataOnEnter or GetData(dwEffect)) then
            begin
              if (not AsyncTransfer) then
                DoDrop(ShiftState, ClientPt, dwEffect);
            end else
              dwEffect := DROPEFFECT_NONE;
            Result := S_OK;
          except
            // We must not allow exceptions to escape from any of the COM methods since
            // COM doesn't support exceptions.
            dwEffect := DROPEFFECT_NONE;
            Result := E_UNEXPECTED;
          end;
        end;

        if (DropTargetHelper <> nil) then
          DropTargetHelper.Drop(DataObj, pt, dwEffect)
        else
          if (FDragImageHandle <> 0) and (FTarget <> nil) then
            ImageList_DragLeave(FTarget.Handle);
      finally
        // clean up!
        if (not AsyncTransfer) then
        begin
          ClearData;
          FDataObject := nil;
          FTarget := nil;
        end;
        FDropTargetHelper := nil;
      end;
    end;

修改后的代码TCustomDropTarget.Drop

    function TCustomDropTarget.Drop(const dataObj: IDataObject; grfKeyState: Longint;
      pt: TPoint; var dwEffect: Longint): HResult;
    var
      ShiftState: TShiftState;
      ClientPt: TPoint;
    begin
      FScrollTimer.Enabled := False;

      try
        // Protect resources against exceptions in OnDrop event handler.
        try
          // Refuse drop if we have lost the data object somehow.
          // This can happen if the drop is rejected in one of the other IDropTarget
          // methods (e.g. DragOver).
          if (not Enabled) or (FDataObject = nil) then
          begin
            dwEffect := DROPEFFECT_NONE;
            Result := E_UNEXPECTED;
          end else
          begin

            ShiftState := KeysToShiftStatePlus(grfKeyState);

            // Create a default drop effect based on the shift state and allowed
            // drop effects (or an OnGetDropEffect event if implemented).
            if (FTarget <> nil) then
              ClientPt := FTarget.ScreenToClient(pt)
            else
              ClientPt := pt;
            dwEffect := GetValidDropEffect(ShiftState, ClientPt, dwEffect);

            // Get data from source and generate an OnDrop event unless we failed to
            // get data.
            try
              if (FGetDataOnEnter or GetData(dwEffect)) then
              begin
                if (not AsyncTransfer) then
                  DoDrop(ShiftState, ClientPt, dwEffect);
              end else
                dwEffect := DROPEFFECT_NONE;
              Result := S_OK;
            except
              // We must not allow exceptions to escape from any of the COM methods since
              // COM doesn't support exceptions.
              dwEffect := DROPEFFECT_NONE;
              Result := E_UNEXPECTED;
              raise; // <--- Why can't I get the exception
            end;
          end;

          if (DropTargetHelper <> nil) then
            DropTargetHelper.Drop(DataObj, pt, dwEffect)
          else
            if (FDragImageHandle <> 0) and (FTarget <> nil) then
              ImageList_DragLeave(FTarget.Handle);
        finally
          // clean up!
          if (not AsyncTransfer) then
          begin
            ClearData;
            FDataObject := nil;
            FTarget := nil;
          end;
          FDropTargetHelper := nil;
        end;
      except
        raise; // <--- Why can't I get the exception
      end;
    end;

2 个答案:

答案 0 :(得分:6)

您无法在Drop()中引发异常并在应用的代码中捕获它。安德的原始评论很清楚:

// We must not allow exceptions to escape from any of the COM methods since
// COM doesn't support exceptions.

Drop()TCustomDropTarget接口方法的IDropTarget.Drop()实现。在IDropTarget函数内部调用DoDragDrop()个方法,该函数由启动拖动的应用程序调用。 Drop()会在您应用的流程中运行,但您的应用不会调用它。因此,即使引发异常是安全的(事实并非如此),也无法放置try/except块来捕获异常,因为COM将检测到异常并作为失败传回启动应用程序,而不是您的应用程序。您唯一的选择是处理OnDrop事件处理程序中的错误,而不会引发异常。

答案 1 :(得分:3)

另一个选择是 - 在您的OnDrop事件中 - 只需收集所需的数据(即,丢弃的文件)并将它们存储在应用程序的TStringList中,然后将消息发布到表单的消息队列以通知它下降。

这样,删除文件的实际处理将在程序的正常上下文中处理,因此您可以正常方式处理异常。