尝试在Delphi XE6中发送密钥失败

时间:2014-05-11 07:09:10

标签: delphi

以下是我用来将Ctrl + Shift + S键发送到PDF文档的完整例程。它应该显示保存对话框但不能这样做。

该过程使用GetFiles打开驻留在sFolder中的pdf文档。 sFolder中只有一个pdf文档。

从注释掉的行中可以看出,我也尝试了sndkey32但没有成功。

procedure TForm1.Button1Click(Sender: TObject);
var
  oBrowser: TBrowseForFolder;
  oList: TStringDynArray;
  sFile: string;
  sFolder: string;
  oShellExecuteInfo: TShellExecuteInfo;
begin
  oBrowser := TBrowseForFolder.Create(self);
  oBrowser.Execute;
  sFolder := oBrowser.Folder;
  oBrowser.Free;
  if DirectoryExists(sFolder) then begin
    oList := TDirectory.GetFiles(sFolder, '*.pdf', TSearchOption.soAllDirectories);
    if Length(oList) > 0 then begin
      for sFile in oList do begin
        FillChar(oShellExecuteInfo, SizeOf(oShellExecuteInfo), 0);
        oShellExecuteInfo.cbSize := SizeOf(TShellExecuteInfo);
        with oShellExecuteInfo do begin
          fMask := SEE_MASK_NOCLOSEPROCESS;
          Wnd := Application.Handle;
          lpFile := PChar(sFile);
          nShow := SW_SHOWNORMAL;
        end;
        if ShellExecuteEx(@oShellExecuteInfo) then begin
          ShowWindow(oShellExecuteInfo.Wnd, 1);
          SetForegroundWindow(oShellExecuteInfo.Wnd);
          Winapi.Windows.SetFocus(oShellExecuteInfo.Wnd);
          SendKey(Ord('s'), [ssCtrl, ssShift], False);
//        if sndkey32.AppActivate('adobe') then
//        sndkey32.SendKeys('^+S', False);
        end;
      end;
    end;
  end;
end;

procedure TForm1.SendKey(key: Word; const shift: TShiftState; specialkey: Boolean);
type
  TShiftKeyInfo = record
    shift: Byte;
    vkey: Byte;
  end;
  ByteSet = set of 0 .. 7;
const
  shiftkeys: array [1 .. 3] of TShiftKeyInfo = ((shift: Ord(ssCtrl); vkey: VK_CONTROL), (shift: Ord(ssShift); vkey: VK_SHIFT), (shift: Ord(ssAlt); vkey: VK_MENU));
var
  flag: DWORD;
  bShift: ByteSet absolute shift;
  j: Integer;
begin
  for j := 1 to 3 do begin
    if shiftkeys[j].shift in bShift then keybd_event(shiftkeys[j].vkey, MapVirtualKey(shiftkeys[j].vkey, 0), 0, 0);
  end;
  if specialkey then flag := KEYEVENTF_EXTENDEDKEY
  else flag := 0;
  keybd_event(key, MapVirtualKey(key, 0), flag, 0);
  flag := flag or KEYEVENTF_KEYUP;
  keybd_event(key, MapVirtualKey(key, 0), flag, 0);
  for j := 3 downto 1 do begin
    if shiftkeys[j].shift in bShift then keybd_event(shiftkeys[j].vkey, MapVirtualKey(shiftkeys[j].vkey, 0), KEYEVENTF_KEYUP, 0);
  end;
end;

1 个答案:

答案 0 :(得分:3)

窗口oShellExecuteInfo.Wnd是Delphi流程中的一个窗口。您将其指定为Application.Handle。您似乎希望它将成为PDF查看器的主窗口,但事实并非如此。

因此您需要找到PDF查看器的主窗口。这需要调用EnumerateWindows来获取所有顶级窗口。然后,对于每一个,使用GetWindowThreadProcessId来测试窗口是否由PDF查看器进程拥有。

其他一些评论:

  1. 调用API函数时忽略错误检查。
  2. 您应该使用SendInput而不是keybd_event
  3. 泄漏ShellExecuteEx返回的进程句柄。
  4. ShellExecuteEx可能根本不返回进程句柄。这取决于文件关联的设置方式,以及Acrobat是否已在运行。
  5. 您可能需要等到新进程完成启动才能发送输入。
  6. 您的程序似乎假设已安装的PDF查看器是Acrobat。如果不是怎么办?