6

我们的应用程序用 Delphi 编写,生成一系列报告,其中大部分是 PDF 格式,生成时会自动打开。Adobe X 引入了一项默认启用的功能“启动时启用保护模式”。报告 pdf 文件使用“ShelExecute”打开。

var 
  pdfFile: string; 
begin 
  pdfFile := 'C:\Users\Ronaldo\Documents\appName\reports\file.pdf'; 
  ShellExecute(0, 'open', PChar(pdfFile), '', '', SW_SHOW);
  // 
end;

由于这个新的 Adob​​e Reader 新设置,在 Win 7 或 Vista 下,我们在打开文档时收到错误消息。双击文档打开它不会有任何问题。有没有办法禁用受保护的方法 - 或另一种方法来打开文档而不会出现错误(解决方法)?

*更多信息 *

PDF文件正在我们的服务器应用程序上生成,流式传输到客户端,客户端生成pdf(使用Write) - 首先我虽然这可能是问题 - 但再次,为什么双击工作正常。

我创建了一个虚拟应用程序,除了使用上面相同的代码打开 pdf 之外什么都不做,它可以工作。我已经检查了应用程序的权限 - 都是一样的 - 唯一的区别是使用正确的安装程序在操作系统上安装了一个不工作的应用程序 - 我刚刚创建并把它放在那里的另一个(虚拟的)。

其中一条评论询问了文件关联 - 这应该不是问题,因为应用程序成功启动了 Adob​​e reader - Adob​​e reader 然后给了我“拒绝访问”错误消息。双击同一个文件可以正常工作。

新信息 - 2011 年 3 月 30 日 - 下午 2:50 - 新西兰时间

我对代码进行了更改,只是为了测试应用程序本身和虚拟应用程序之间的唯一区别。现在,它不是自动获取文件路径和文件名,而是打开一个 OpenDialog - opendialog 的 Filename 属性用作 ShellExecute 的参数(如 Ken 回答后的注释所述) - 它可以工作。为什么会这样,当您从打开的对话框中获取文件名时,它可以工作 - 请注意,我没有从对话框中打开文件 - 我正在获取文件名,并将其用作 ShellExecute 的参数。

更新的代码示例

当用户点击“生成报告”按钮时,报告生成后自动打开。除此之外,还有一个网格,显示了迄今为止为该用户生成的所有报告 - 这是该网格双击的代码:

if GetSelectedReport <> nil then // this will check if the user selected an report
  if TReportItemState(GetSelectedReport.State)  in [risGenerated,risViewed] then // checks if the report selected is in the correct state to be displayed.
  begin
    fileName := TClientReportManager.Singleton.Directory+'\'+GetSelectedReport.Filename; // a string with the filePath + fileName
    ShellExecute(0, 'open', pchar(fileName), '','', SW_MAXIMIZE); // command to open the file
  end;

我对 Opendialog 工作的第一个猜测是,打开的对话框会更改 CurrentDir - 所以我已经尝试使用 SetCurrentDir 和 ChDir 将当前目录更改为文件所在的目录。没有成功。

Win 7下,文件路径翻译为C:\Users\Ronaldo\Documents\CompanyName\AppName

4

2 回答 2

3

我认为您不能在代码中完全禁用它。如果可以的话,它将破坏保护模式的全部目的(防止恶意软件利用 .pdf 文件关联)。不过,您也许可以通过合法的方式解决它。:)

我怀疑它与open你使用的动词有关ShellExecute。您假设(可能不正确)open动词在 Win7 上的保护模式下的作用与在 Adob​​e Reader 和 Windows 的早期版本上的作用相同。(注意:我的系统上没有安装那个版本的 Acrobat;这都是猜测。)

我要尝试的第一件事是将调用更改ShellExecute为如下:

ShellExecute(0, nil, PChar(pdfFile), nil, nil, SW_NORMAL);

第一个变化是nil作为第二个参数传递。这会告诉 Windows 您希望发生什么默认操作。例如,这可以view代替open.

我还将文件名后面的两个参数也更改为 nil。这比使用空字符串 ('') 更具可读性。

最后的变化是在最后一个参数中;我通常使用SW_NORMAL而不是SW_SHOW,只是因为这告诉 Windows 以默认大小和位置显示它;这可能是应用程序保存的内容,并将影响用户的偏好(如果有)。

如果这不起作用,是时候在 Windows 注册表中四处游荡(小心!! )。regedit在开始菜单的搜索控件中打开,然后导航到 HKEY_CLASSES_ROOT。向下滚动文件扩展名,直到找到 的条目.pdf,然后双击该分支。您会看到Default, (无论如何,在我的系统上)AcroExch.Document带有Content Typeof application/pdf

继续在左窗格中的树下找到AcroExch.Document,然后展开它。您会在那里看到一些值(同样来自我的机器),如下图所示。展开Shell分支,您将看到已定义的动词,以及与它们关联的命令。在我的机器上(再次),我有一个Open动词,其命令设置为"C:\Program Files (x86)\Adobe\Reader 9.0\Reader\AcroRd32.exe" "%1".

RegEdit 左窗格RegEdit 值窗格

(忍受我 - 我们快到了。我保证。)

您可以通过检查默认值来查看双击的不同之处(单击Shell左侧窗格,然后查看(Default)右侧的设置。然后检查命令行(在上面的第二张图片中,它是Open)以查看如果将任何内容传递到 Acrobat Reader 应用程序,则进行什么切换。(如果您无法确定哪个是默认设置,请右键单击 Windows 资源管理器中的 .pdf 文件,然后查看上下文菜单中的粗体项目。)

如果没有"%1"传递的参数,则需要将相同的参数添加到提供给ShellExecute. 例如,如果参数是/v,您可以将调用修改ShellExcute为如下所示:

ShellExecute(0, nil, PChar(pdfFile), PChar('/v'), nil, SW_NORMAL);
于 2011-03-29T23:23:35.783 回答
1

我已经把它抛在了后面,但现在我有时间回去尝试解决问题。

我发现,客户端应用程序正在使用 GetEnvironmentVariable('USERPROFILE') 来获取报告所在文件夹的一部分。这给了我类似 Windows 7 上的 'c:\users\user_name\' 的信息 - 然后添加一个类似“My Documents\CompanyFolder\ProductFolder”的常量。

在 win XP 下这工作正常,但在 Win 7 下,由于某种原因,UAC 似乎不允许您直接并专门引用“我的文档”——相反,您需要使用“文档”。

我更改了常量以删除“我的文档”部分,并添加了一个函数来使用参数 CSIDL_Personal 和函数检索私人用户文档文件夹:

function GetSpecialFolderPath(folder : integer) : string;
const
  SHGFP_TYPE_CURRENT = 0;
var
  path: array [0..MAX_PATH] of char;
begin
  if SUCCEEDED(SHGetFolderPath(0,folder,0,SHGFP_TYPE_CURRENT,@path[0])) then
    Result := path
  else
    Result := '';
end;

并调用 GetSpecialFolderPath(CSIDL_Personal) 之类的函数。

感谢大家花时间发表评论和答案。

只想补充一点,这个答案在我的情况下是正确的答案。@Ken White 的答案可能是其他人的正确答案。

于 2011-05-04T02:59:05.157 回答