1

我正在尝试TDropFileTargetMelanderDragDrop套件的组件。目标是在拖放文件后执行某些任务。另外,如果在处理过程中出现问题,我想收到异常。

似乎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;
4

2 回答 2

6

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

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

Drop()isTCustomDropTargetIDropTarget.Drop()接口方法的实现。IDropTarget方法在函数内部调用,该DoDragDrop()函数由启动拖动的应用程序调用。 Drop()在您的应用程序的进程中运行,但它不被您的应用程序调用。因此,即使引发异常是安全的(事实并非如此),您也没有地方可以放置try/except块来捕获异常,因为 COM 会检测到异常并作为失败返回给启动应用程序,不是你的应用程序。您唯一的选择是在OnDrop不引发异常的情况下处理事件处理程序中的错误。

于 2012-04-29T03:14:38.587 回答
3

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

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

于 2012-04-29T06:45:29.133 回答