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 ファイルはサーバー アプリケーションで生成され、クライアントにストリーミングされ、クライアントは (Write を使用して) PDF を生成します。

上記の同じコードを使用してpdfを開くだけのダミーアプリを作成しましたが、機能します。私はアプリケーションの権限を確認しました - すべて同じです - 唯一の違いは、動作していないものは適切なインストーラーを使用して OS にインストールされていることです - もう一方 (ダミーのもの) は作成してそこにドロップしました。

コメントの 1 つがファイルの関連付けについて尋ねます - アプリケーションが 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で使っている動詞と関係があると思いますShellExecuteopenWin7 の保護モードで動詞が以前のバージョンの Adob​​e Reader と Windows で行ったのと同じように動作すると(おそらく間違って) 想定しています。(:私のシステムにはそのバージョンの Acrobat がインストールされていません。これはすべて憶測です。)

最初に試したいのは、呼び出しをShellExecute次のように変更することです。

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

最初の変更はnil、2 番目のパラメーターとして渡すことです。これにより、Windows は、既定のアクションを実行する必要があることを伝えます。これは、たとえば、viewの代わりになる場合がありopenます。

また、ファイル名の後の 2 つのパラメーターも nil に変更しました。これは、空の文字列 ('') を使用するよりも読みやすいです。

最終的な変更は最後のパラメーターにあります。これは、デフォルトのサイズと位置が何でSW_NORMALあれSW_SHOW、Windowsに表示するように指示するためです。これは、アプリケーションによって保存されたものである可能性があり、ユーザーの設定 (存在する場合) を有効にします。

これでうまくいかない場合は、Windows レジストリを(慎重に!! ) 調べてみましょう。regeditスタート メニューの検索コントロールで開き、HKEY_CLASSES_ROOT に移動します。のエントリが見つかるまでファイル拡張子を下にスクロールし、.pdfそのブランチをダブルクリックします。が表示されますがDefault、これは (とにかく私のシステムでは)AcroExch.Documentの.Content Typeapplication/pdf

が見つかるまで左ペインのツリーを下に進みAcroExch.Document、展開します。下の画像でわかるように、そこにいくつかの値が表示されます (これも私のマシンからのものです)。ブランチを展開Shellすると、定義された動詞とそれに関連付けられたコマンドが表示されます。私のマシンには (再び)、単一のOpen動詞があり、そのコマンドは に設定されてい"C:\Program Files (x86)\Adobe\Reader 9.0\Reader\AcroRd32.exe" "%1"ます。

RegEdit 左ペインRegEdit 値ペイン

(我慢してください - 私たちはもうすぐそこにいます. 私は約束します。)

デフォルト値を調べることで、ダブルクリックの動作が異なることを確認できます (Shell左側のペインをクリックし、右側のペインで設定されている内容を確認し(Default)ます。次に、コマンドライン (上の 2 番目の画像では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 に答える