拖放在我的delphi项目中不再起作用

时间:2010-12-03 12:44:27

标签: windows delphi file drag-and-drop messages

这个话题显然已经在这里反复出现了,但现在我从我的角度来看已经没有选择了。

操作系统:Windows XP SP3

所以,这是我在我的应用中使用的 RichEdit的拖放示例

procedure TForm1.AcceptFiles( var msg : TMessage ); // or TWMDROPFILES
const
  cnMaxFileNameLen = 255;
var
  i,
  nCount     : integer;
  acFileName : array [0..cnMaxFileNameLen] of char;
begin
  // find out how many files we're accepting
  nCount := DragQueryFile( msg.WParam, // or msg.Drop
                           $FFFFFFFF,
                           acFileName,
                           cnMaxFileNameLen );

  // query Windows one at a time for the file name
  for i := 0 to nCount-1 do
  begin
    DragQueryFile( msg.WParam, { or msg.Drop} i,
                   acFileName, cnMaxFileNameLen );

    // do your thing with the acFileName
    MessageBox( Handle, acFileName, '', MB_OK );
  end;

  // let Windows know that you're done
  DragFinish( msg.WParam ); // or msg.Drop
end;

问题是在最近的一些更改之后(unforutinetly我没有使用任何SVN,所以我无法跟踪哪个提交引入了这个问题)拖放不再起作用。

我在每个可能以某种方式相关(称为)的事件中都没有成功运行断点:

RichEditMouseOver;

RichEditChange;

FormClick;

我的应用正在处理这些WM:

procedure WMDropFiles(var Msg: TWMDROPFILES); message WM_DROPFILES;

procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;

procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA;

procedure WMGetMinMaxInfo(var AMsg: TWMGetMinMaxInfo); message WM_GETMINMAXINFO;

procedure CMDialogKey(var Msg: TCMDialogKey ); message CM_DIALOGKEY;

在表格上使用TRichEdit的空白项目 - 一切正常。

还尝试将DragAcceptFiles() Form1.Handle更改为RichEdit.Handle - 仍然没有运气。

当回显nCountacFileName参数时,acFileName没有拖动文件的文件路径...为什么????

目前我不知道是什么让acFileName参数丢失拖动文件路径。你能说一下问题隐藏在哪里吗?

3 个答案:

答案 0 :(得分:4)

摘自official Microsoft support forum

  

不存在的可能原因   能够拖拽将文件拖放到   应用程序可以是UAC完整性   水平(IL)。在Vista中启用UAC   或Win7,不允许拖放   从低IL过程发生到高   IL进程默认情况下。请检查   您的申请是否提升   (当管理员运行时)问题   发生的情况。

如果您不想禁用UAC,可以尝试禁用UIPI(用户界面权限隔离)。

打开注册表并转到:HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Policies \ System

添加一个名为EnableUIPI的新DWORD(32位)值并将其设置为0.

重新启动机器并查看它是否符合您的要求。

答案 1 :(得分:3)

我要在这里尝试一下心理调试;你说它“不再起作用”,暗示它在某些方面起作用。虽然你还没有提到你正在使用哪种操作系统,但我也认为你使用的是Windows Vista或Windows 7(或相关的服务器版本)。

我怀疑发生的事情是您的应用程序作为与shell不同的用户或权限级别运行。 Windows不允许拖动(尤其是文件拖动)数据从一个权限级别的应用程序转移到另一个权限级别。如果您从IDE运行此命令,并且IDE以管理员身份运行,则生成的进程也在该级别运行。

检查以确保您的应用程序实际上以登录用户身份运行。我被这个被咬了太多次,并且非常微妙,以至于对于发生的事情来说,它永远不会立即显而易见。

答案 2 :(得分:2)

我担心我不是拖拉文件实际工作原理的专家。所以我无法通过你的代码弄清楚出了什么问题。

我能做的就是给你我使用的代码。它现在适用于我在Delphi 2009上的XP,Vista和Windows 7.当我以前在Windows 98和Windows XP上使用Delphi 4时,它也有效。

也许您可以使用此功能找出代码中的错误,或者您可能想尝试使用或调整此代码。它最初出自以下书:“Delphi 3 - 用户界面设计”,第169-171页。

如果我遗漏了一个重要的例程,请在评论中告诉我,我会编辑我的答案以包含它。

type
  TMainForm = class(TForm)
    procedure WMDropFiles(var WinMsg: TMessage);
              message wm_DropFiles;
    procedure AppMessageHandler(var Msg: TMsg; var Handled: Boolean);

procedure TMainForm.FormShow(Sender: TObject);
begin
  DragAcceptFiles(Handle, true);
  Application.OnMessage := AppMessageHandler;
end;

procedure TLogoAppForm.WMDropFiles(var WinMsg: TMessage);
const
  BufSize = 255;
var
  TempStr : array[0..BufSize] of Char;
  NumDroppedFiles, I: integer;
  Filenames: TStringList;
begin
  NumDroppedFiles := DragQueryFile(TWMDropFiles(WinMsg).Drop, $ffffffff, nil, 0);
  if NumDroppedFiles >= 1 then begin
    Filenames := TStringList.Create;
    for I := 0 to NumDroppedFiles - 1 do begin
      DragQueryFile(TWMDropFiles(WinMsg).Drop, I, TempStr, BufSize);
      Filenames.Add(TempStr);
    end;
    OpenFiles(Filenames, '');
    Filenames.Free;
  end;
  DragFinish(TWMDropFiles(WinMsg).Drop);
  WinMsg.Result := 0;
end;

procedure TLogoAppForm.AppMessageHandler(var Msg: TMsg; var Handled: Boolean);
begin
  if (Msg.Message = WM_DropFiles) and IsIconic(Application.Handle) then begin
    Perform(Msg.Message, Msg.Wparam, Msg.lParam);
    Handled := true;
  end
end;