ショートカットの情報取得するには?

解決


黒鬚  2005-11-05 23:22:49  No: 18466

黒鬚です。
ショートカットの情報を取得したいのですが
思うように動きません。

ここの過去ログをみて
http://www2.big.or.jp/~osamu/Delphi/Tips/key.cgi?key=6#0099.txt
を参考にしてがんばって作ってみましたが
モジュールエラーが発生します。
モジュールエラーの発生は CoUninitialize で起こっています。

function  TForm1.GetLinkFileName(FName: String): String;
var
  HR:         HRESULT;
  psl:        IShellLink;
  ppf:        IPersistFile;
  wsz:        array [0..MAX_PATH] of WideChar;
  szGotPath:  array [0..MAX_PATH] of Char;
  wfd:        WIN32_FIND_DATA;
begin
  CoInitialize(Nil);

  HR := CoCreateInstance(CLSID_ShellLink, Nil, CLSCTX_INPROC_SERVER, IShellLink, psl);
  if SUCCEEDED(HR) then begin
    HR := psl.QueryInterface(IPersistFile, ppf);
    if SUCCEEDED(HR) then begin
      MultiByteToWideChar(CP_ACP, 0, PChar(FName), -1, wsz, MAX_PATH);
      HR := ppf.Load( wsz, STGM_READ );
      if SUCCEEDED(HR) then begin
        HR := psl.Resolve(Application.Handle, SLR_ANY_MATCH);
        if SUCCEEDED(HR) then begin
          HR := psl.GetPath(szGotPath, MAX_PATH, wfd, SLGP_SHORTPATH );
          if SUCCEEDED(HR) then Result := szGotPath;
        end;
      end;
      ppf._Release;
    end;
    psl._Release;
  end;
  CoUninitialize;
end;


黒鬚  2005-11-06 00:13:11  No: 18467

すみません。

ppf._Release;
psl._Release;
この2つを削除すると問題が出なくなりました。
問題あるのかも


Mr.XRAY  URL  2005-11-06 00:15:48  No: 18468

黒鬚さんのエラー対策でないのですが,参考になれば幸いです.
以下は,私が使用しているコードです.動作確認はWindowXP + Delphi5
ですが,実行ファイルはWin98,WinMe,Win2k,WinXPで動作しています.

Formに以下を配置します.
TButton
TMemo
TOpenDialog

uses ShlObj,ActiveX,ComObj;

{$R *.DFM}

{ TForm1 }

//=============================================================================
//  ファイル選択ダイアログを表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
     OpenDialog1.Filter:='ショートカット(*.lnk)|*.LNK';
     if OpenDialog1.Execute then begin
       GetLinkPath(OpenDialog1.FileName);
     end;
end;
//=============================================================================
//  IShellLinkを使用するにusesにShlObjが必要
//  IPersistFileを使用するにはusesにActiveXが必要
//  CreateComObjectを使用するにはusesにComObjが必要
//=============================================================================
procedure TForm1.GetLinkPath(FileName: String);
var
     ShellLink   : IShellLink;
     PersistFile : IPersistFile;
     FilePath    : array[0..MAX_PATH] of char;
     WorkDir     : array[0..MAX_PATH] of char ;
     Arg         : array[0..MAX_PATH] of char;
     FileLink    : String;
     wsz         : array[0..MAX_PATH] of WideChar;
     pfd         : TWin32FindData;
begin
     FileLink := FileName;
     ShellLink := CreateComObject(CLSID_ShellLink) as IShellLink;
     OleCheck(ShellLink.QueryInterface(IPersistFile,PersistFile));

     Assert(Assigned(PersistFile));
     MultiByteToWideChar(CP_ACP,0,PChar(FileLink),-1,wsz,MAX_PATH);
     OleCheck(PersistFile.Load(wsz,0));
     OleCheck(ShellLink.GetPath(FilePath,MAX_PATH,pfd,SLGP_RAWPATH));
     OleCheck(ShellLink.GetWorkingDirectory(WorkDir,MAX_PATH));
     OleCheck(ShellLink.GetArguments(Arg, MAX_PATH));

     //上から順にプログラムパス名,作業フォルダ,起動オプション
     //実際のPCではリンク先としてパス名に起動オプションが付加されている
     Memo1.Clear;
     Memo1.Lines.Add(ExtractFileName(FileName));
     Memo1.Lines.Add(StrPas(FilePath));
     Memo1.Lines.Add(StrPas(WorkDir));
     Memo1.Lines.Add(StrPas(Arg));
end;


Mr.XRAY  URL  2005-11-06 00:17:11  No: 18469

おっ,一足遅かったですね.


黒鬚  2005-11-06 01:08:05  No: 18470

Mr.XRAY さん
早速ですが、別件の質問があって
書き込み前にちょっと試してみました。

えっと、私のやり方だと、パス名がショート(〜が付く)になってまして
質問しようと思ったのですが、Mr.XRAY さんのは
そのままロングパス名で取得できました。
こういうのを、ことわざで・・・・・・・
っていうんでしょうね?(−−;

ありがとうございました。

ちなみに、パスもファイル名もショートになっているのを
すべて一括でロングにする方法って知ってますか?
昔、ファイルやディレクトリ名の単体には  FindFirst で
変換してたけど、このやり方だとパスを一つ一つ分割してからの処理で
面倒なんですよね。
もし、しってらっしゃったら教えてください。


Mr.XRAY  URL  2005-11-06 02:21:51  No: 18471

>変換してたけど、このやり方だとパスを一つ一つ分割してからの処理で
>面倒なんですよね。

でもこれしかないようです.私が取得した情報では.

//=============================================================================
//  短いファイル名を長いファイル名に変換する関数
//  途中のディレクトリ名が短い場合を考慮して再帰処理
//=============================================================================
function TForm1.ShortToLong(ShortName: String): String;
var
     S        : TSearchRec;
     FileDir  : String;
     FileName : String;
begin
     FileDir  := ExtractFileDir(ShortName);
     FileName := ExtractFileName(ShortName);
     if Length(FileName)=0 then begin
       Result := FileDir;
       exit;
     end;
     FileDir :=ShortToLong(FileDir);
     FileDir :=IncludeTrailingBackslash(FileDir);
     try
       if FindFirst(FileDir+FileName,faAnyFile,S)<>0 then begin
         Result := ShortName
       end else begin
         Result :=FileDir+S.Name;
       end;
     finally
       FindClose(S);
     end;
end;


Mr.XRAY  URL  2005-11-06 02:34:26  No: 18472

すみません.現用のアプリで使用しているものをそのままアップして
いまいました.動作確認していません.多分現用のものなのでOKかと...
(ショートカットを見つけるか作らないと...簡単か?)

原理は,デリミタを除いたディレクトリ名を順番に長いファイル名に
していくという,黒鬚さんのやり方を関数にしたものです.


Mr.XRAY  URL  2005-11-06 05:08:03  No: 18473

HDDを見ていたら,こんなのがありました.
使えるのではないかと思います.
interface部でもimplementation部も構いません.この関数を使用する前に
以下のコードを追加して下さい.

function GetLongPathNameA(ShortPathName: PChar; LongPathName: PChar;
         cchBuffer: Integer): Integer; stdcall; external 'kernel32.dll';

//====================================================================
//  kernel32.dll内の関数GetLongPathNameを利用
//  GetLongPathNameGetFullPathNameと違いWin98でも大文字と小文字を区
//  別して取得可能
//====================================================================
function TForm1.ShortToLongPath(ShortName: String): String;
var
    Buffer : array[0..MAX_PATH] of Char;
begin
     if (GetLongPathNameA(PChar(ShortName),Buffer,SizeOf(Buffer)))<>0 then
     begin
       Result:=Buffer;
     end else
     begin
       Result:=ShortName;
     end;
end;


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加