Delphi Tips 
-----------------------------

キーワード:ファイル

>> Index

01/22 短いファイル名を長いファイル名に変換したい(COM版)。
12/31 リンクファイルから参照先のファイル名を得る
06/27 ファイルの更新日時を得る
06/25 FindFirst でアイコンを変更したディレクトリを検索できない
06/25 FindFirst による4文字以上の拡張子の判別
05/14 ディレクトリのファイルを列挙する
09/27 短いファイル名を長いファイル名に変換したい。
09/27 エクスプローラからファイルをドラッグ&ドロップする
09/26 ファイルを削除してゴミ箱に移動させたい。
09/24 Windows 特殊フォルダの Class ID List
09/22 長いファイル名を短いファイル名に変換したい
09/08 任意のドライブをセクタ単位で読み書きする
09/08 フォルダのタイムスタンプを変更する
08/26 他のアプリの起動パスを取得する
02/11 カレントユーザのデスクトップディレクトリを得る
02/11 TFileStream で標準出力に表示
02/11 エクスプローラで使われるアイコンを取得・変更する
02/11 クリップボードにコピーされたファイル・ディレクトリ
02/11 リムーバブルドライブの種類を判別する
02/08 リードオンリーファイルを Assign/Reset で読もうとするとエラーになる
02/08 複数プログラムから同一内容のメモリを参照/更新する
02/08 OpenDialogでたくさんファイルを選択するとエラー
02/08 TDriveComboBoxの内容の更新
02/08 NTで他のアプリが開いているファイルを知る

最終更新: 4504 日前

0273  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/24 西坂良幸 rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2006/01/22 <> 編集
短いファイル名を長いファイル名に変換したい(COM版)。

エクスプローラは内部的には、短い名前を使っているようです。
ということは、シェルのCOMインターフェースのメソッドが使えるということです。
[Tips:233]のCOM版を考えてみましょう。

uses ShlObj,Comobj,ActiveX;

function ShortToLongFileName(const ShortName: string): string;
var
  Desktop: IShellFolder;
  pIDList: PITEMIDLIST;
  NameS: String;
  NameW: WideString;
  Len : integer;
  Buffer: array[0..MAX_PATH] of Char;
  // 以下は値は使わない
  pDummy: PCHAR;
  pchEaten, Attributes: ULONG;
begin
  pIDList := Nil;
  // フルパス化
  Len := GetFullPathName(PChar(ShortName), 0, PChar(result), pDummy);
  SetLength(NameS, Len);
  GetFullPathName(PChar(ShortName), Len, PChar(NameS), pDummy);
  // ワイド文字列に転換
  NameW := NameS;
  // IShellFolderを生成(解放は自動)
  OleCheck(SHGetDesktopFolder(Desktop));
  // IDリストをえる
  OleCheck(Desktop.ParseDisplayName(0, Nil, PWideChar(NameW), pchEaten, pIDList, Attributes));
  if not SHGetPathFromIDList(pIDList, Buffer) then
  raise EConvertError.Create('ファイルを変換できません。');
  Result := StrPas(Buffer);
end;


WideStringを使うことを覗けば、IShellFolderのParseDisplayNameメソッドとSHGetPathFromIDList
を使うだけです。[Tips:233]よりすっきりしましたか。

※ 使用できるOS、バァージョンに注意して下さい。
参照: [Delphi-ML:7322] <その他Windows関連> <Windows> <PASCAL>

0099  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2005/12/31 長山 編集
リンクファイルから参照先のファイル名を得る

IShellLinkを使用すれば出来ます。

    CoInitialize(NULL);

    HRESULT HR;
    IShellLink *psl;
    IPersistFile *ppf;
    WideChar wsz[MAX_PATH];
    char szGotPath[MAX_PATH];
    WIN32_FIND_DATA wfd;

    HR = CoCreateInstance(CLSID_ShellLink, NULL,
                CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
    if(SUCCEEDED(HR)){
        HR = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
        if(SUCCEEDED(HR)){
            MultiByteToWideChar(CP_ACP, 0, "ショートカット.lnk", -1,
                    wsz, MAX_PATH );
            HR = ppf->Load( wsz, STGM_READ );
                if(SUCCEEDED(HR)){
                    HR = psl->Resolve(Application->Handle, SLR_ANY_MATCH);
                    if(SUCCEEDED(HR)){
                        HR = psl->GetPath(szGotPath, MAX_PATH,
                                (WIN32_FIND_DATA *)&wfd, SLGP_SHORTPATH );
                        Edit2->Text = szGotPath;
                    }
                }
            }
            ppf->Release();
        }
        psl->Release();
    }
    CoUninitialize();



Delphi翻訳版 (関数です)

uses
  Windows, SysUtils, ShlObj, ActiveX, ComObj;
  
const IID_IPersistFile: TGUID= (D1:$0000010B;D2:$0000;D3:$0000;D4:($C0,$00,$00,$00,$00,$00,$00,$46));

function ExtractStringFromLinkFile( Target:TFileName ): String;
var
    R   : HRESULT;
    SL  : IShellLink;
    PF  : IPersistFile;
    Wrk : array[0..MAX_PATH] of WideChar;
    Path: array[0..MAX_PATH] of Char;
    WFD : WIN32_FIND_DATA;
begin
    Result := '';
    CoInitialize( NIL );

    R := CoCreateInstance( CLSID_ShellLink, NIL, CLSCTX_INPROC_SERVER, IID_IShellLinkA, SL );
    if Succeeded( R ) then
    begin
        R := SL.QueryInterface( IID_IPersistFile, PF );
        if Succeeded( R ) then
        begin
            MultiByteToWideChar( CP_ACP, 0, PChar(Target), -1, Wrk, MAX_PATH );
            R := PF.Load( Wrk, STGM_READ );
            if Succeeded( R ) then
            begin
                R := SL.Resolve( 0{Application.Handle}, SLR_ANY_MATCH );
                if Succeeded( R ) then
                begin
                    SL.GetPath( Path, MAX_PATH, WFD, SLGP_SHORTPATH );
                    Result := Path;
                end;
            end;
        end;
    end;

    CoUninitialize;
end;
参照: [builder:5475] <ShellApi> <Windows>

0173  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/03/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/27 osamu 編集
ファイルの更新日時を得る

Windows 的な方法としては、FindFirst/FindClose を使って、得られた TSerchRec を読みます。

別解として、PASCAL の FileAge 関数を使った方法を、ひきさんが以下のホームページで解説してくださっています。

[Delphi壁の穴]-[その二:システムを覗く]
http://hp.vector.co.jp/authors/VA009712/take/delphi/kabesys.htm#datetimefile1
http://hp.vector.co.jp/authors/VA009712/take/delphi/kabesys.htm#datetimefile2
参照: <日時> <PASCAL>

0331  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
FindFirst でアイコンを変更したディレクトリを検索できない

Delphi7, WinXPです。XPにはフォルダのアイコンイメージを変更することができるのですが、これを適用したフォルダをFindFirstは認識しません。

この投稿に簡単な解決法は投稿されませんでした。FindFirstFileEx API や Shell 関連の API を使うことで回避できるかもしれないとの意見がありました。
参照: [Delphi-ML:73372] <Windows>

0330  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 2003/06/25 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2003/06/25 osamu 編集
FindFirst による4文字以上の拡張子の判別

Q.FindFirst,FindNextを使用してファイル名を取得しているのですが、PATH定数を "C:\TEST\*.jpg" と指定した場合、拡張子が「.jpg」のファイルだけでなく退避用にリネームした”XXXX.Jpg_”といったファイルまでヒットしてしまいます。

A.WinXPには4文字以上の拡張子を正しく認識させるためのレジストリが用意されています。以下の方法を試してみてはいかがでしょうか。Win2000でも同じことができるかどうかはわかりません。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem の Win95TruncatedExtensions を 0 にして再起動。
参照: [Delphi-ML:73374] <Windows>

0274  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/24 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 2001/05/14 jkaneko@fujita.co.jp 編集
ディレクトリのファイルを列挙する

以下のようにするのが定石です。
ポイントは,
  2バイト文字の2バイト目に '\' が来る可能性を考慮する
    -> IsPathDelimiter 関数
  FindFirst が成功したときのみ FindClose を呼ぶ。
    -> [Delphi-ML:17508]
  repeat until を使うとループがスマートに書ける
  '.' や '..' といった特殊ディレクトリも列挙される
といったところです。

SearchRec.FindData には見つかったファイルに関するさらに多くの情報が詰まっています。ヘルプを参照しましょう。

procedure Form1.EnumFiles(DirectoryName: string);
var
  SearchRec: TSearchRec;
begin
  // 一番後ろに '\' がついていなければ付ける
    DirectoryName:= IncludeTrailingBackslash(DirectoryName);

  // FindFirst が成功した場合のみ FindClose を呼ぶ必要がある
  if 0=FindFirst(DirectoryName+'*.*', faAnyFile, SearchRec) then try
    repeat
      if SearchRec.Attr and faDirectory <> 0 then begin
        // カレントディレクトリや親ディレクトリをスキップ
        if (SearchRec.Name='.') and (SearchRec.Name='..') then
          Continue;
        // ディレクトリに対する処理
        // SearchRec.Name にディレクトリ名が入っている
        // たとえば、Memo1.Lines.Add('Dir :'+DirectoryName+SearchRec.Name);
      end else begin
        // ファイルに対する処理
        // SearchRec.Name にファイル名が入っている
        // たとえば、Memo1.Lines.Add('File:'+DirectoryName+SearchRec.Name);
      end;
    until 0<>FindNext(SearchRec);
  finally
    FindClose(SearchRec);
  end;
end;
参照:

0233  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/03 西坂良幸 rev 1.6
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/27 西坂良幸 編集
短いファイル名を長いファイル名に変換したい。

長いファイル名を短いファイル名にするのは、APIにGetShortPathNameという関数があるで簡単ですが([Tips:68])、逆の長いファイル名にするのはちょっと工夫が必要です。

APIのFindFirstFile関数を使うとパラメータのWIN32_FIND_DATA構造体のcAlternateFileNameに短いファイル名あり、長いファイル名はcFileNameにあります。
したがって、長い→短い、短い→長いの変換は基本的には、ファイル名を使ってもう一度FindFirstしてやればいいわけです。

効率を無視すれば次のようものでしょうか。
この関数ではドライブレターの大文字小文字は変換されませんので、必要であれば後から大文字に変換してください。

function ShortToLongFileName(ShortName: String):String;
var
  SearchRec: TSearchRec;
begin
  result:= '';
  // フルパス化
  ShortName:= ExpandFileName(ShortName);
  // 長い名前に変換(ディレクトリも)
  while LastDelimiter('\', ShortName) >= 3 do begin
    if FindFirst(ShortName, faAnyFile, SearchRec) = 0 then
      try
        result := '\' + SearchRec.Name + result;
      finally
        // 見つかったときだけ Close -> [Delphi-ML:17508] を参照
        FindClose(SearchRec);
      end
    else
      // ファイルが見つからなければそのまま
      result := '\' + ExtractFileName(ShortName) + result;
    ShortName := ExtractFilePath(ShortName);
    SetLength(ShortName, Length(ShortName)-1); // 最後の '\' を削除
  end;
  result := ShortName + result;
end;

[Tips:273]に同様の結果を得るCOM版があります。
参照: [Delphi-ML:3333] [Delphi-ML:7320] [Delphi-ML:7322] [Delphi-ML:17508] [Tips:68] [Tips:273]

0218  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/26 西坂良幸 rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/27 西坂良幸 編集
エクスプローラからファイルをドラッグ&ドロップする

一度はやってみたいんですよね。MLでも多いスレッドです。
「Delphi2.0Q&A120選」(大野元久著)にもあります。

WM_DropFilesメッセージを捕まえて、DragQueryFile関数で処理するわけですが、受け取る側のスタイルを準備しなければなりません。
これは、一般的なフォームのOnCreateイベントで
DragAcceptFiles(Handle,True);
を使うよりも、CreateParamsをオーバーライドするのがベターだそうです。

// 定義部
 type
  TForm1 = class(TForm)
  ・・省略・・
  private
    procedure CreateParams(var Params: TCreateParams);override;
    procedure WMDropFiles(Var Msg: TWMDropFiles); Message WM_DropFiles;
  public
  end;

// 実装部
procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  // 受け取れる準備をする
  Params.ExStyle := Params.EXStyle or WS_EX_ACCEPTFILES;
end;

// ファイル1個の場合−−メモに読み込ませる。
procedure TForm1.WMDropFiles(Var Msg: TWMDropFiles);
Var
  FileName: Array[0..MAX_PATH] of Char;
Begin
  Count := DragQueryFile(Msg.Drop, 0, FileName, SizeOf(FileName));
  Memo1.Lines.LoadFromFile(String(FileName));
  DragFinish(Msg.Drop);
End;

//今度は複数の場合−−リストボックスにファイル名
procedure TForm1.WMDropFiles(Var Msg: TWMDropFiles);
Var
  FileName: Array[0..MAX_PATH] of Char;
  i, Count: integer;
Begin
  ListBox1.Items.clear;
  // 第二パラメータを-1にするとドロップ数が取得できる
  Count := DragQueryFile(Msg.Drop, DWord(-1), FileName, SizeOf(FileName));
  for i := 0 to count - 1 do
  begin
    DragQueryFile(Msg.Drop, i, FileName, SizeOf(FileName));
    ListBox1.items.add(String(FileName));
  end;
  DragFinish(Msg.Drop);
End;

最後のDragFinishを忘れないように。
参照: [Delphi-ML:3137] [Delphi-ML:8536] [Delphi-ML:31274] <ShellApi> <Windows>

0275  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/26 西坂良幸 rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/26 西坂良幸 編集
ファイルを削除してゴミ箱に移動させたい。

SHFileOperation関数を使えば、ファイル単位でもフォルダーごとでもゴミ箱に移動させることができます。
注意事項としては、必ずフルパスでなければならないということです。

ちょっと変な関数名ですが・・・

Uses Shellapi;

procedure SendToRecycleBin(FileList: TStrings; Dlg: boolean);
var
  LpFileOp:TSHFILEOPSTRUCT;
  FileNames: string;
  i: integer;
begin
  if FileList.Count = 0 then exit;
  // #0をデリミタとした文字列を作る
  for i := 0 to FileList.Count - 1 do
    FileNames := FileNames + FileList[i] + #0;
  // ターミネイタにもう一度#0をつける
  FileNames := FileNames + #0;
  with LpFileOp do
  begin
    Wnd := Application.Handle;
    wFunc := FO_DELETE;
    pFrom := PChar(FileNames);
    pTo:= nil;
    fFlags := FOF_ALLOWUNDO;
    if not Dlg then fFlags := fFlags or FOF_SILENT;
    hNameMappings := nil;
    lpszProgressTitle := nil;
  end;
  SHFileOperation(LpFileOp);
end;

// テスト
procedure TForm1.Button1Click(Sender: TObject);
var
  Flist :TStrings;
begin
  Flist := TStringlist.Create;
  try
    Flist.Add('C:\Program Files\Borland\Delphi 4\Projects\*.~df');
    Flist.Add('C:\Program Files\Borland\Delphi 4\Projects\*.~pa');
    SendToRecycleBin(FList, true);
  finally
    Flist.free;
  end;
end;
参照: [Delphi-ML:3443] [Delphi-ML:5005] <ShellApi> <Windows>

0196  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/07/07 osamu rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/24 K.Takaoka 編集
Windows 特殊フォルダの Class ID List


SHGetFolderPath, SHGetFolderLocation, SHGetSpecialFolderPath, SHGetSpecialFolderPath といった API で Windows が特別に扱うフォルダのパスを得ることができます.
これらのフォルダはユーザ環境によって異なるため, 常に API を利用して取得するようにすると問題のないアプリケーションが開発できます.

フォルダ名:CSIDL名(プログラムで利用できる定数名)
{CLSIDL}
ディレクトリ名

マイコンピュータ: CSIDL_DRIVES
{20D04FE0-3AEA-1069-A2D8-08002B30309D}
マイコンピュータはディレクトリにリンクしていません

ネットワークコンピュータ: CLSIDL_NETWORK, CSIDL_NETHOOD
{208D2C60-3AEA-1069-A2D7-08002B30309D}
ネットワークコンピュータはディレクトリにリンクしていません

マイドキュメント: CSIDL_PERSONAL
{450D8FBA-AD25-11D0-98A8-0800361B1103}
C:\My Document
C:\WinNT\Users\UserName\Personal

ごみ箱: CSIDL_BITBUCKET
{645FF040-5081-101B-9F08-00AA002F954E}
C:\Recycled.Bin

コントロールパネル: CSIDL_CONTROLS
{21EC2020-3AEA-1069-A2DD-08002B30309D}
コントロールパネルはディレクトリにリンクしていません

プリンタ: CSIDL_PRINTERS, CSIDL_PRINTHOOD
{2227A280-3AEA-1069-A2DE-08002B30309D}
プリンタフォルダはディレクトリにリンクしていません


他にも

CSIDL_COOKIES, CSIDL_DESKTOP, CSIDL_DESKTOPDIRECTORY, CSIDL_FAVORITES, CSIDL_FONTS, CSIDL_HISTORY, CSIDL_INTERNET, CSIDL_INTERNET_CACHE, CSIDL_PROGRAMS, CSIDL_RECENT, CSIDL_SENDTO, CSIDL_STARTMENU, CSIDL_STARTUP, CSIDL_TEMPLATES

などといったものが Win95/98/NT4/2K で共通に利用できます.

WinNT/2K においては CSIDL_COMMON_*** という形式で全ユーザ共通のフォルダを指定できるものが多くあり, Win2K にはさらに多くの定数が新設されています.

基本的には MSDN などの Microsoft の公式な文書を読むことになりますが, HKEY_CLASSES_ROOT\CLSID\ 以下を探すことで, アプリケーション固有のものを発見することができます.

たとえば、
「受信トレイ」
{00020D75-0000-0000-C000-000000000046}


といったものです.

これらを利用して 'プリンタ.{2227A280-3AEA-1069-A2DE-08002B30309D}' という名前のフォルダを作ることで、任意の場所にプリンタフォルダを追加できます。

参考: http://msdn.microsoft.com/library/sdkdoc/Shell/Functions/CSIDL.htm
参照: [Delphi-ML:10601] <Windows>

0068  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/22 osamu 編集
長いファイル名を短いファイル名に変換したい

GetShortPathName APIを使いましょう。

function LongToShortFileName(Const LongName: String):String;
var
  Len: integer;
begin
  Len := GetShortPathName(PChar(LongName), PChar(result), 0);
  SetLength(result, len);
  if GetShortPathName(PChar(LongName), PChar(result), Len) = 0 then
    Raise EConvertError.Create('ファイルが見つかりません。');
end;

ファイルが実在しないと例外が発生します。

逆に、短いファイル名を長いファイル名にするには [Tips:233] を見てください。
参照: [builder:5092] [Tips:233] <Windows>

0240  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/08 osamu 編集
任意のドライブをセクタ単位で読み書きする

Q:
MS-DOS Ver.2.1でフォーマットされたFDをWin95で読込みたいのですが、どのようにすればよいのでしょうか?
セクタ単位で読込む方法が解りません。

A:
'\\.\A:' で該当のドライブ( A: の部分を適宜変更)に対して CreateFile() すればアクセスできます。

# You can use the CreateFile function to open a disk drive
# or a partition on a disk drive. The function returns a
# handle to the disk device; that handle can be used with
# the DeviceIOControl function. The following requirements
# must be met in order for such a call to succeed:
#
# The caller must have administrative privileges for the
# operation to succeed on a hard disk drive.
# The lpFileName string should be of the form \\.\PHYSICALDRIVEx
# to open the hard disk x. Hard disk numbers start

注意として GetDiskFreeSpace() でセクタサイズを調べて FILE_FLAG_NO_BUFFERING でアクセスしてください。
参照: [Delphi-ML:32482]

0143  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/08 osamu 編集
フォルダのタイムスタンプを変更する

ファイルのタイムスタンプを変更するのはできるのですがフォルダのタイムスタンプはどのようにして変更したらよいのでしょうか?

procedure ChangeDirTime(DirName : String;Date : TDateTime);
var
  FHandle   : integer;

Begin
 FHandle := CreateFile(Pchar(DirName),  { ディレクトリ名最後に\はいらない }
   GENERIC_WRITE,    { 書きこみ許可しないと変えられない }
   FILE_SHARE_Read,   { 最低他からアクセスできないとハンドルがもらえない }
   nil,     { セキュリティは無視(いいのかな?) }
   OPEN_EXISTING,    { ディレクトリは存在していることを前提 }
   FILE_FLAG_BACKUP_SEMANTICS,   { APIのヘルプをみてね }
   0);
 FileSetDate(FHandle,DateTimeToFileDate(Date));
 CloseHandle(FHandle);
End;

タイムスタンプの設定にAPIのSetFileTimeを使う手もありますがフォルダならこれで十分です。

D3+Win98 では動きませんでした。NT では動くのかな???
参照: [Delphi-ML:24889] <Windows>

0182  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/08 osamu rev 1.2
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/26 西坂良幸 編集
他のアプリの起動パスを取得する


> (ウィンドウハンドルの場合)
> GetWindowLong(hwnd, GWL_HINSTANCE) でモジュールハンドルを取り出す。
> (モジュールハンドルの場合)
> GetModuleFileName(hModule, strBuffer, nBufferSize) でファイル名を得る。

 残念ですがこの方法では、他のアプリの起動パス は取得できません。自分自身のExe名しか取得できません。(私も最初はこれではまった。)(^.^)

 モジュールハンドルはプロセス毎に独立して管理されるので、他のアプリ(他のプロセス)のモジュールハンドルを持ってきても意味がありません。

http://www.microsoft.com/japan/support/kb/articles/J041/6/32.htm

にシステム内で稼働中のプロセスを列挙する方法がでてますから、参考にしてください。ウィンドウハンドルが判っているのでしたら、
GetWindowthreadProcessID でプロセスIDを求めて、列挙中にこれと合致するプロセスを探せばよいでしょう。

たとえば、Win95/98用(WinNTではダメ)ですが、


uses TLHelp32;

// ハンドルからファイル名を得る
function GetProcesFileNameFrom(Handle: hWnd):string;
var
  PID: DWORD;
  SnapShot: THandle;
  ProcessEntry32: TProcessEntry32;
begin
  // ハンドルから作成スレッドを調べてプロセスIDを得る
  GetWindowThreadProcessId(Handle, @PID);
  // TProcessEntry32構造体の初期化
  ProcessEntry32.dwSize := SizeOf(TProcessEntry32);
  // システム中の情報のスナップショットをとる
  SnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  try
    // 最初のプロセスの検索
    if Process32First(SnapShot, ProcessEntry32) then
    begin
      repeat
        // IDが一致したら
        if ProcessEntry32.th32ProcessID = PID then
        begin
          Result := string(ProcessEntry32.szExeFile);
          break;
        end;
      // 次のプロセスの検索
      until Process32Next(SnapShot, ProcessEntry32) = False;
    end;
  finally
    CloseHandle(SnapShot);
  end;
end;

などです。
参照: [Delphi-ML:30032] <アプリケーション> <Windows>

0163  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
カレントユーザのデスクトップディレクトリを得る

>実行中に現在の(ユーザの)「デスクトップ」ディレクトリのパスを取得したい
>のですが、どうすれば良いのでしょうか?

こんなの有ります。
uses ShellAPI, SHlObj, ComObj, ActiveX;
  :
  :
function GetDesktopFolder: string;

  function GetDispName(shi: IShellFolder; pidl: PItemIDList): string;
  var DispName: TStrRet;
  begin
    shi.GetDisplayNameOf(pidl, SHGDN_FORPARSING, DispName);

    if DispName.uType = STRRET_CSTR then
      Result := DispName.cStr
    else if DispName.uType = STRRET_OFFSET then
      Result := PCHAR(LongInt(pidl) + DispName.uOffset)
    else
      Result := WideCharToString(DispName.pOleStr);
  end;

  var Pidl: PItemIDList;
      DesktopFolderI: IShellFolder;

begin
  OleCheck(SHGetSpecialFolderLocation(0, CSIDL_DESKTOPDIRECTORY, Pidl));
  try
    OleCheck(SHGetDesktopFolder(DesktopFolderI));
    Result := GetDispName(DesktopFolderI, Pidl);
  finally
    CoTaskMemFree(Pidl);
  end;
end;
参照: [Delphi-ML:31606] <Windows>

0161  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
TFileStream で標準出力に表示

> テキストファイルの入出力は TStringList でやると便利です。
> そこで、コンソールアプリケーションの標準出力でも使いたいなと、
> SaveToFile('con') を実行したところ例外で失敗しました。
> VCLソースを追いかけてみたところ、TFileStream.Create() で例外が起きていました。
>
> ところが、SaveToFile('nul') を実行したところ、なにも出力されないとはいえ
> 例外が発生することなく実行できました。
>
> 簡単に使えないのはしかたないのですが、この違いはなんでしょうね?

これ、'con'の代わりに'conout$'だと行けるみたいですね。

ところで、ちょっと横道にそれますけど、'con'だと仮にopen出来ても
リダイレクトした場合にまでコンソールに表示されて場合によっては
不便じゃありませんか?
その場合は以下のようにした方が良いかと。

uses
  windows, classes, sysutils;

var
  s : TStringList;
  hs : THandleStream;
begin
  s := TStringList.Create;
  try
    hs := THandleStream.Create(GetStdHandle(STD_OUTPUT_HANDLE));
    try
      s.SetText('一行目'#10'二行目'#10'三行目'#10);
      s.SaveToStream(hs);
    finally
      hs.free;
    end;
  finally
    s.free;
  end;
end.
参照: [Delphi-ML:31323] <Windows>

0153  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
エクスプローラで使われるアイコンを取得・変更する

> Windowsでディレクトリなどに使われるアイコンを変更するなどの
> プログラムもあるみたいですが、そういったシステムで使われる
> アイコンを取得したいと思っています。

レジストリの HKEY_LOCAL_MACHINE の下に

Software\Microsoft\Windows\CurrentVersion\explorer\Shell Icons

というキーがあり、ここに番号の文字列を作り、アイコンのファイル名とインデックスを設定することによりアイコンが設定可能です。
参照: [Delphi-ML:26403] <Windows> <アイコン>

0147  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
クリップボードにコピーされたファイル・ディレクトリ

> クリップボードからペーストなのですが、どのようにしたらファイル名
> なのか確認できますか?その取り出し方も教えていただけないでしょうか?

プログラム上、考慮することが2点(だけかな?)、あります。

1) Explorer上で「コピー」した場合は、クリップボード内にCF_HDROPフォーマットのデータが入るようになってます。この場合、ファイルの有無はこのフォーマットの有無で判断できます。例は下のほうに置いておきます。

2) IE4が出てから、Explorerに「アドレス」なるコンボボックスが付きやがりまして、ここでディレクトリ名の「コピー」、できちまうんスよ、ったく。こいつ、テキスト形式(CF_TEXT)なんでね、これも考慮するとくりゃ、テキストがファイル名として正しいのか、白黒つけなきゃならないんスね。あ〜こりゃこりゃ。ちと面倒なコトをするハメになりそうっスよ、ったく。くぁ〜、まぃったねぇ。あっしぁ、面倒みきれませんぜ。なんせ あっし、ほれ、バカなんで。

// uses Clipbrd, ShellAPI;
procedure TForm1.Button1Click(Sender: TObject);
var
  i,
  n: integer;
  hDrop: THandle;
  szFile:  array[0..MAX_PATH-1] of Char;
begin
  if HasFormat(CF_HDROP) then
  begin
    hDrop := GetAsHandle(CF_HDROP);
    n := DragQueryFile(hDrop, $FFFFFFFF, szFile, MAX_PATH); // -1かな?(64bit用)
    Caption := Format('FileCount : %d', [n]);
    for i := 0 to n - 1 do
    begin
      DragQueryFile(hDrop, i, szFile, MAX_PATH);
      ListBox1.Items.Add(szFile);
    end;
  end;
end;
参照: [Delphi-ML:25073] <その他Windows関連> <Windows>

0140  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
リムーバブルドライブの種類を判別する

結局結論は出たのでしょうか???
参照: [Delphi-ML:24577] <Windows>

0133  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/08 osamu 編集
リードオンリーファイルを Assign/Reset で読もうとするとエラーになる

Reset する前に FileMode 変数をセットしましょう。
参照: [Delphi-ML:23966]

0061  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/08 osamu 編集
複数プログラムから同一内容のメモリを参照/更新する

Win32用に、中村@NECさんが、File Mapping を利用して実現したクラスを [Delphi-ML:19603] で紹介されています。
ただ、添付ファイルは Web からは取れません。
どこか他からダウンロードしないと。。。
参照: [Delphi-ML:19603] <Windows> <メモリ>

0070  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/08 osamu 編集
OpenDialogでたくさんファイルを選択するとエラー

ファイル名を保存するバッファが 8KB 固定のために起こります。
VCL に手を入れるか、自分で GetOpenFileName API を呼ぶしか回避できません。
参照: [builder:5117] <バグ> <ダイアログ>

0017  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/08 osamu 編集
TDriveComboBoxの内容の更新

ネットワークドライブの割当てをした後、TDriveComboBoxにて割当てたドライブを反映させたいのですが、方法が解りません。

    DriveComboBox1.TextCase:=DriveComboBox1.TextCase;

たぶんこれが一番楽な方法だと思います。
非常に裏わざ臭いですが。。。
参照: [Delphi-ML:7162] <System> <バグ> <コンポーネント >

0002  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/08 osamu 編集
NTで他のアプリが開いているファイルを知る

WindowsNT上ならば、
   http://www.ntinternals.com/
に NTFilemon があります。
ソースが公開されているので、参考になるかもしれません。
参照: [Delphi-ML:18558] <Windows>

[新規作成] [最新の情報に更新]

How To
Lounge
KeyWords

Tips
Delphi
Home
Osamu Takeuchi osamu@big.or.jp