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

标签 delphi exception drag-and-drop

我正在尝试 TDropFileTarget Melander 的 DragDrop 的组成部分套房。目标是在拖放文件后执行某些任务。另外,如果在处理过程中出现问题,我希望收到异常。

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

最佳答案

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

// We must not allow exceptions to escape from any of the COM methods since
// COM doesn't support exceptions.
Drop()TCustomDropTargetIDropTarget.Drop() 的实现接口(interface)方法。 IDropTarget方法在 DoDragDrop() 内部调用函数,由发起拖动的应用调用。 Drop()在您的应用程序的进程中运行,但它不被您的应用程序调用。因此,即使引发异常是安全的(事实并非如此),您也无处可放置 try/except阻止捕获异常,因为 COM 会检测到异常并将其作为失败传递回启动应用程序,而不是您的应用程序。您唯一的选择是处理 OnDrop 中的错误。事件处理程序而不引发异常。

关于delphi - 使用 Melander 的 DragDrop 套件时如何允许异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10367026/

相关文章:

php - 返回 javascript 代码时如何在 PHP/Dojo 中正确生成异常

java - 如何有效地使用 InterruptedException

c# - 拒绝基于对象数据的拖放?

Delphi:是否应该手动释放 PChar 数组的已分配元素?

java - 为什么会有这样的输出?

delphi - 如何使用DLL中包含的标志?

objective-c - 就像在 Interface Builder 中一样在窗口之间画线

drag-and-drop - 是否可以创建自己的拖放 Mailchimp 模板?

delphi - 如何将该值转换为有效日期?

C# Dll 库不向 Delphi 应用程序返回输出参数值