Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2019年07月21日] [更新 2019年07月21日] Delphi サンプルプログラム集
494_コマンドプロンプトを ShellExecuteEx 関数で起動
動作確認等 Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32
494_ShellExecuteEX_CmdPrompt.zip [5,286 KB] 2019年07月21日版 (EXE 同梱)







コマンドプロンプトや他のアプリを ShellExecuteEx 関数で起動


ShellExecuteEx 関数を使用して,他のプログラム (アプリ) を起動する際の参考サンプルです.
ShellExecuteEx 関数の引数は TShellExecuteInfo レコード型の変数 1 つだけです.このレコード型のメンバに ShellExecute 関数の引数と同じ内容の値を設定します.ShellExecute 関数とは違い,起動したプロセス ID の値を取得することがてきます.
ShellExecuteEx 関数は,拡張子の関連付けされたプログラムを起動して,指定したファイルを表示することができます.

本ページでは起動するプログラムとしてコマンドプロセッサを起動してコマンドプロンプトを表示します.コマンドプロセッサの実行ファイル名は cmd.exe です.
コマンドプロンプトについては,以下のページにも参考記事やサンプルコードがあります.



上のリンクの記事以外にも,当サイトには,アプリの起動やコマンドプロンプトに関する記事やサンプルコードがあります.






01_コマンドラインオプションとコマンドを指定して起動


コマンドラインのオプションと,コマンドを指定してコマンドプロンプトを起動します.
コマンドプロンプトの起動時に CD コマンドを実行し,カレントディレクトリを C:\ にします.起動後は,コマンドプロンプトも自アプリのどちらも操作可能な状態になります.



図1
実行開始画面
  • コマンドプロンプトを起動

リスト1
ShellExecuteEx 関数を使用して,コマンドプロンプトを起動
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  Winapi.ShellAPI;

{$R *.DFM}

//-----------------------------------------------------------------------------
//  ShellExecuteEx関数を使用して,指定したファイルを実行する
//  この関数の戻り値は TShellExecuteInfo.hInstApp の値
//
//  uses に Winapi.ShellAPI が必要
//-----------------------------------------------------------------------------
function RunExeFile(hWnd: HWND; AFile: string; AParameters: string;
   Verb: string; nShow: Cardinal): Cardinal;
var
  LInfo : TShellExecuteInfo;
begin
  FillChar(LInfo, SizeOf(LInfo), 0);
  LInfo.cbSize := SizeOf(LInfo);
  LInfo.fMask  := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_NO_UI;

  LInfo.lpFile       := PChar(AFile);
  LInfo.lpParameters := PChar(AParameters);
  LInfo.Wnd    := hWnd;
  LInfo.lpVerb := PChar(Verb);
  LInfo.nShow  := nShow;

  ShellExecuteEx(@LInfo);

  //ShellExecuteExは成功するとhInstAppに33以上の値を返す
  Result := LInfo.hInstApp;
  if Result >= 33 then begin
    CloseHandle(LInfo.hProcess);
  end;
end;

//=============================================================================
//  ShellExecuteEx 関数の使用例
//  コマンドプロンプトを起動
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LExeFile   : string;
  LParamText : string;
begin
  LExeFile   := 'Cmd.exe';
  LParamText := '/k cd /d c:\';

  RunExeFile(0, LExeFile, LParamText, '', SW_SHOW);
end;

end.


コマンドプロンプトでは,コマンドラインのパラメータでカレントディレクトリを指定することができますが,一般のアプリで起動時のディスレクトりを指定するには,ShellExecuteEx 関数のレコード型の引数である TShellExecuteInfo の lpDirectory メンバの値で設定します.
以下はコマンドプロンプトの場合です.起動直後はパラメータで指定したディレクトリがカレントディレクトリになっていますが,ドライブを D:\ にすると lpDirectory メンバに設定した値になっていることが確認できます.



[備考]
コマンドプロンプトのカレントディレクトリはドライブ単位です.ドライブ毎にカレントディレクトリが存在します.一般のアプリのカレントディレクトリはプロセス単位です.1 つのプロセスのカレントディレクトリは 1 つだけですす.


図2
カレントディレクトリの確認

リスト2
ShellExecute 関数を使用して,コマンドプロンプトを起動
  // 起動時のディレクトリの指定
  // コマンドプロンプトのカレントディレクトリはドライブ単位であることに注意
  LInfo.lpDirectory := 'D:\000';

  LInfo.lpFile       := PChar(AFile);
  LInfo.lpParameters := PChar(AParameters);
  LInfo.Wnd    := hWnd;
  LInfo.lpVerb := PChar(Verb);
  LInfo.nShow  := nShow;




02_コマンドプロンプトや起動アプリのプロセス生成を待つ


ShellExecuteEx 関数でアプリを起動すると,そのアプリのプロセスの情報が取得できます.しかし,アプリによってはプロセスの生成まで時間がかかることがあります.そこで,本サンプルでは起動するアプリのプロセスが生成されるまで待つ処理を追加しています.プロセスが生成された後,プロセス ID の値を取得しおけば,起動したアプリの操作に利用できます.
ここでは起動したアプリの終了処理にプロセス ID を使用しています.
プロセス ID の値に相当するウィンドウを調べれば,起動したアプリがまだ起動中か終了しているかを確認でき.必要があれば終了させることができます.



図3
実行画面
  • [Button2] は起動したアプリの終了用

リスト3
ShellExecuteEx 関数で起動するアプリがプロセスを生成まで待つ
起動したプロセスを,ウィンドウハンドルを使用して終了する処理を追加
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    FProcessID : Cardinal;
    function CheckValidProcess(APID: Cardinal; AClose: Boolean): Boolean;
  end;

var
  Form1: TForm1;

implementation

uses
  Winapi.ShellAPI;

{$R *.DFM}

//-----------------------------------------------------------------------------
//  ShellExecuteEx関数を使用して,指定したファイルを実行する
//  この関数の戻り値は起動したプロセスのプロセス ID の値
//
//  uses に Winapi.ShellAPI が必要
//-----------------------------------------------------------------------------
function RunExeFile(hWnd: HWND; AFile: string; AParameters: string;
   Verb: string; nShow: Cardinal): Cardinal;
var
  LInfo : TShellExecuteInfo;
  LRet  : Cardinal;
begin
  Result := 0;

  FillChar(LInfo, SizeOf(LInfo), 0);
  LInfo.cbSize := SizeOf(LInfo);
  LInfo.fMask  := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_NO_UI;

  LInfo.lpFile       := PChar(AFile);
  LInfo.lpParameters := PChar(AParameters);
  LInfo.Wnd    := hWnd;
  LInfo.lpVerb := PChar(Verb);
  LInfo.nShow  := nShow;

  ShellExecuteEx(@LInfo);

  //ShellExecuteExは成功するとhInstAppに33以上の値を返す
  if LInfo.hInstApp >= 33 then begin
    //プロセス生成完了まで待つ
    repeat
      LRet := WaitForInputIdle(LInfo.hProcess, 50);
      Application.ProcessMessages;
    until LRet <> WAIT_TIMEOUT;

    Result := GetProcessId(LInfo.hProcess);
    CloseHandle(LInfo.hProcess);
  end;
end;

//=============================================================================
//  フォームを閉じる時の処理
//=============================================================================
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  // このプログラムで起動したプロセスを終了
  CheckValidProcess(FProcessID, True);
end;

//=============================================================================
//  ShellExecuteEx 関数の使用例
//  コマンドプロンプトを表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LExeFile   : string;
  LParamText : string;
begin
  // 複数起動させない場合
  if CheckValidProcess(FProcessID, False) then Exit;

  LExeFile   := 'Cmd.exe';
  LParamText := '/k cd /d c:\';

  FProcessID := RunExeFile(0, LExeFile, LParamText, '', SW_SHOW);
  // 上の関数の実行後も起動したアプリは終了していない
end;

//=============================================================================
//  このサンプルプログラムで起動したプロセスを終了
//  本サンプルではコマンドプロンプトを終了
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  CheckValidProcess(FProcessID, True);
  FProcessID := 0;
end;

//-----------------------------------------------------------------------------
//  EnumWindowsのコールバック関数
//  プロセス ID に相当するゥインドウハンドルを取得
//-----------------------------------------------------------------------------
function EnumWndProc(hWindow: HWND; lPar: PNativeUInt):
  Boolean; Stdcall;
var
  LdwProcessID : Cardinal;
begin
  Result := True;

  // ウィンドウハンドルからプロセスIDの値を取得
  GetWindowThreadProcessId(hWindow, LdwProcessID);
  if LPar^ = LdwProcessID then begin
    LPar^ := hWindow;
    Result := False;
  end;
end;

//-----------------------------------------------------------------------------
//  指定したプログラムが起動しているかを検出
//  必要に応じて終了させる
//
//  戻り値が False の場合
//  対象のプログラムは起動していない
//  別の方法で終了しているかも知れない
//  処理が終了すると自動的に終了するプログラムもある
//-----------------------------------------------------------------------------
function TForm1.CheckValidProcess(APID: Cardinal; AClose: Boolean): Boolean;
var
  LhWnd : NativeUInt;
begin
  if APID = 0 then begin
    Result := False;
    Exit;
  end;

  // プロセス ID に相当するウィンドウハンドルを取得
  LhWnd := APID;
  EnumWindows(@EnumWndProc, LPARAM(@LhWnd));
  Result := LhWnd <> APID;

  if Result and AClose then begin
    PostMessage(LhWnd, WM_CLOSE, 0, 0);
  end;
end;

end.


上のコードでは,フォームを閉じると起動したアプリも終了するようになっています.これを,例えば以下のように,起動したアプリの確認処理とすることもできます.



図4
フォームを閉じる時にアプリが起動中かを確認

リスト4
フォームを閉じる時にアプリが起動中かを確認
//=============================================================================
//  フォームを閉じる時の処理
//=============================================================================
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var
  LText : string;
begin
  if CheckValidProcess(FProcessID, False) then begin
    LText := 'コマンドプロンプトが起動したままです' + sLineBreak
           + '確認してください';
    MessageBox(Handle, PChar(LText), '確認', MB_ICONINFORMATION);
    CanClose := False;
  end;
end;


起動したアプリの終了等の操作が必要なく.単に起動するアプリのプロセスの生成を待つだけであれば以下のコードで十分です.
このサンプルでは,アプリを起動したらダイアログを表示するようにしています.



図5
アプリが起動したらダイアログを表示

リスト5
ShellExecuteEx 関数で起動するアプリがプロセスを生成まで待つ
プロセス ID の値が必要ない場合
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  Winapi.ShellAPI;

{$R *.DFM}

//-----------------------------------------------------------------------------
//  ShellExecuteEx関数を使用して,指定したファイルを実行する
//  この関数の戻り値は TShellExecuteInfo.hInstApp の値
//
//  uses に Winapi.ShellAPI が必要
//-----------------------------------------------------------------------------
function RunExeFile(hWnd: HWND; AFile: string; AParameters: string;
   Verb: string; nShow: Cardinal): Cardinal;
var
  LInfo : TShellExecuteInfo;
  LRet  : Cardinal;
begin
  FillChar(LInfo, SizeOf(LInfo), 0);
  LInfo.cbSize := SizeOf(LInfo);
  LInfo.fMask  := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_NO_UI;

  LInfo.lpFile       := PChar(AFile);
  LInfo.lpParameters := PChar(AParameters);
  LInfo.Wnd    := hWnd;
  LInfo.lpVerb := PChar(Verb);
  LInfo.nShow  := nShow;

  ShellExecuteEx(@LInfo);

  Result := LInfo.hInstApp;
  //ShellExecuteExは成功するとhInstAppに33以上の値を返す
  if Result >= 33 then begin
    //プロセス生成完了まで待つ
    repeat
      LRet := WaitForInputIdle(LInfo.hProcess, 50);
      Application.ProcessMessages;
    until LRet <> WAIT_TIMEOUT;

    CloseHandle(LInfo.hProcess);
  end;
end;

//=============================================================================
//  ShellExecuteEx 関数の使用例
//  コマンドプロンプトを表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LExeFile   : string;
  LParamText : string;
begin
  LExeFile   := 'Cmd.exe';
  LParamText := '';
  RunExeFile(0, LExeFile, LParamText, '', SW_SHOW);
  MessageBox(Handle, 'アプリが起動しました', '情報', MB_ICONINFORMATION);
end;

end.




03_起動したコマンドプロンプトやアプリの終了を待つ


起動したアプリのプロセスが終了するまで待つ例です.アプリを起動する関数,本サンプルでは RunExeFile という関数の処理は,起動したアプリが終了するまで終了しません.
本サンプルも,前項のサンプルと同じように起動したアプリを自アプリから終了させる関数を作成して実装しています.

本サンプルを起動してコマンドプロンプトを起動した後,フォームの [X] ボタンをクリックしてもフォームは閉じませんが,[X] ボタンをクリックした後にコマンドプロンプトを終了すると自動的にフォームが閉じます.
この動作仕様を変更するには,希望する仕様に応じた処理が必要です.



リスト6
ShellExecuteEx 関数で起動したアプリが終了するまで待つ
起動したプロセスを,ウィンドウハンドルを使用して終了する処理を追加
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    function CheckValidProcess(APID: Cardinal; AClose: Boolean): Boolean;
  end;

var
  Form1: TForm1;

implementation

uses
  Winapi.ShellAPI;

{$R *.DFM}

var
  FProcessID : Cardinal;

//-----------------------------------------------------------------------------
//  ShellExecuteEx関数を使用して,指定したファイルを実行する
//  この関数の戻り値は TShellExecuteInfo.hInstApp の値
//
//  プロセスが起動したらそのプロセス ID の値を引数に返す
//  この値を起動してプロセスの強制終了に使用する
//
//  uses に Winapi.ShellAPI が必要
//-----------------------------------------------------------------------------
function RunExeFile(hWnd: HWND; AFile: string; AParameters: string;
   Verb: string; nShow: Cardinal; var AProcessID: Cardinal): Cardinal;
var
  LInfo : TShellExecuteInfo;
  LRet  : Cardinal;
begin
  FillChar(LInfo, SizeOf(LInfo), 0);
  LInfo.cbSize := SizeOf(LInfo);
  LInfo.fMask  := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_NO_UI;

  LInfo.lpFile       := PChar(AFile);
  LInfo.lpParameters := PChar(AParameters);
  LInfo.Wnd    := hWnd;
  LInfo.lpVerb := PChar(Verb);
  LInfo.nShow  := nShow;

  ShellExecuteEx(@LInfo);

  //ShellExecuteExは成功するとhInstAppに33以上の値を返す
  Result := LInfo.hInstApp;
  if Result >= 33 then begin
    //プロセス生成完了まで待つ
    repeat
      LRet := WaitForInputIdle(LInfo.hProcess, 50);
      Application.ProcessMessages;
    until LRet <> WAIT_TIMEOUT;

    // プロセスが起動したらプロセス ID の値をグローバル変数に代入
    AProcessID := GetProcessId(LInfo.hProcess);

  //起動したプロセス(アプリ)の終了を待つ処理
    while WaitForSingleObject(LInfo.hProcess, 100) = WAIT_TIMEOUT do begin
      Application.ProcessMessages;
    end;

    CloseHandle(LInfo.hProcess);
  end;
end;

//=============================================================================
//  フォームを閉じる時の処理
//=============================================================================
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  // 以下を実行するとこのプログラムで起動したプロセスを終了
  // CheckValidProcess(FProcessID, True);
end;

//=============================================================================
//  ShellExecuteEx 関数の使用例
//  コマンドプロンプトを表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LExeFile   : string;
  LParamText : string;
begin
  // 複数起動させない場合
  if CheckValidProcess(FProcessID, False) then Exit;

  LExeFile   := 'Cmd.exe';
  LParamText := '/k cd /d c:\';

  RunExeFile(0, LExeFile, LParamText, '', SW_SHOW, FProcessID);
  // 起動したアプリが終了すると以下が実行される
  FProcessID := 0;
end;

//=============================================================================
//  このサンプルプログラムで起動したプロセスを終了
//  本サンプルではコマンドプロンプトを終了
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  CheckValidProcess(FProcessID, True);
  FProcessID := 0;
end;

//-----------------------------------------------------------------------------
//  EnumWindowsのコールバック関数
//  プロセス ID に相当するゥインドウハンドルを取得
//-----------------------------------------------------------------------------
function EnumWndProc(hWindow: HWND; lPar: PNativeUInt):
  Boolean; Stdcall;
var
  LdwProcessID : Cardinal;
begin
  Result := True;

  // ウィンドウハンドルからプロセスIDの値を取得
  GetWindowThreadProcessId(hWindow, LdwProcessID);
  if LPar^ = LdwProcessID then begin
    LPar^ := hWindow;
    Result := False;
  end;
end;

//-----------------------------------------------------------------------------
//  指定したプログラムが起動しているかを検出
//  必要に応じて終了させる
//
//  戻り値が False の場合
//  対象のプログラムは起動していない
//  別の方法で終了しているかも知れない
//  処理が終了すると自動的に終了するプログラムもある
//-----------------------------------------------------------------------------
function TForm1.CheckValidProcess(APID: Cardinal; AClose: Boolean): Boolean;
var
  LhWnd : NativeUInt;
begin
  if APID = 0 then begin
    Result := False;
    Exit;
  end;

  // プロセス ID に相当するウィンドウハンドルを取得
  LhWnd := APID;
  EnumWindows(@EnumWndProc, LPARAM(@LhWnd));
  Result := LhWnd <> APID;

  if Result and AClose then begin
    PostMessage(LhWnd, WM_CLOSE, 0, 0);
  end;
end;

end.


本サンプルのような同期処理にすると,起動したアプリの終了の検出が容易になります.前項のような非同期処理の場合は,起動したアプリを自アプリで終了した時は,そのアプリの終了を検出できますが,起動したアプリ側で終了した場合は終了を検出できません.

前項のような非同期処理の場合は,Button1 クリックでアプリを終了して,そのまま同じアプリや別のアプリを起動できます.
一方,本サンプルのような同期処理の場合は,他のアプリを起動しても Button1 クリックのイベントコードは終了していません.Button1 クリックっで起動中のアプリを終了させても,それは Buton1 クリックのコードを終了させることになりますから,Button1 クリックはトグル操作となります.



起動したアプリの終了等の操作が必要なく.単に起動したアプリの終了を待つだけであれば以下のコードで十分です.
このサンプルでは,起動したアプリが終了したらダイアログを表示するようにしています.



図6
起動したアプリが終了したらダイアログを表示

リスト7
ShellExecuteEx 関数で起動したアプリが終了するまで待つ
プロセス ID の値が必要ない場合
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  Winapi.ShellAPI;

{$R *.DFM}

//-----------------------------------------------------------------------------
//  ShellExecuteEx関数を使用して,指定したファイルを実行する
//  起動したアプリが終了するまで待つ
//  この関数の戻り値は TShellExecuteInfo.hInstApp の値
//
//  uses に Winapi.ShellAPI が必要
//-----------------------------------------------------------------------------
function RunExeFile(hWnd: HWND; AFile: string; AParameters: string;
   Verb: string; nShow: Cardinal): Cardinal;
var
  LInfo : TShellExecuteInfo;
begin
  FillChar(LInfo, SizeOf(LInfo), 0);
  LInfo.cbSize := SizeOf(LInfo);
  LInfo.fMask  := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_NO_UI;

  LInfo.lpFile       := PChar(AFile);
  LInfo.lpParameters := PChar(AParameters);
  LInfo.Wnd    := hWnd;
  LInfo.lpVerb := PChar(Verb);
  LInfo.nShow  := nShow;

  ShellExecuteEx(@LInfo);

  //ShellExecuteExは成功するとhInstAppに33以上の値を返す
  Result := LInfo.hInstApp;
  if Result >= 33 then begin
  //起動したプロセス(アプリ)の終了を待つ処理
    while WaitForSingleObject(LInfo.hProcess, 100) = WAIT_TIMEOUT do begin
      Application.ProcessMessages;
    end;

    CloseHandle(LInfo.hProcess);
  end;
end;

//=============================================================================
//  ShellExecuteEx 関数の使用例
//  コマンドプロンプトを表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LExeFile   : string;
  LParamText : string;
begin
  Button1.Enabled := False;

  LExeFile   := 'Cmd.exe';
  LParamText := '';

  RunExeFile(0, LExeFile, LParamText, '', SW_SHOW);
  MessageBox(Handle, '起動したアプリが終了しました', '情報', MB_ICONINFORMATION);

  Button1.Enabled := True;
end;

end.





04_ShellExecuteEx 関数で起動したアプリの強制終了


上のサンプルで使用している WM_CLOSE メッセージでは終了できないアプリケーションの場合,プロセス ID の値から OpenProcess 関数でプロセスのハンドルの値を取得します.そのプロセスハンドルの値を使用して,TerminateProcess 関数で終了させることができます.



リスト8
ShellExecuteEx 関数で起動したアプリを強制終了させるコード
//-----------------------------------------------------------------------------
//  指定したプロセス ID のプロセスが起動しているかを検出
//  必要に応じて強制終了させる
//
//  戻り値が False の場合
//  対象のプロセスは存在しない
//  他の方法で終了していることもある
//  目的の処理が終了すると自動的に終了するプログラムもある
//-----------------------------------------------------------------------------
function TForm1.CheckValidProcess(APID: Cardinal; ATerminate: Boolean): Boolean;
var
  LhProcHandle : Cardinal;
begin
  if APID = 0 then begin
    Result := False;
    Exit;
  end;

  // Terminate(プロセスの終了)アクセスモードでOpenProcess
  // APID は起動したプロセスのプロセス ID の値
  LhProcHandle := OpenProcess(PROCESS_TERMINATE, False, APID);
  Result := LhProcHandle <> 0;
  if Result and ATerminate then begin
    try
      TerminateProcess(LhProcHandle, 0);
    finally
      CloseHandle(LhProcHandle);
    end;
  end;
end;





05_管理者権限でコマンドプロンプトやアプリを起動


ShellExecuteEx 関数で起動するアプリを管理者権限で実行するには,TShellExecuteInfo.lpVerb の文字列の値を 'runas' にします.起動するアプリが管理者権限で実行するようになっている場合はこの指定は必要ありません.



図7
管理者への昇格ダイアログが表示される
図8
コマンドプロンプトを管理者権限で起動
  • ウィンドウのキャプションに [管理者] の表示

リスト9
ShellExecuteEx 関数で起動するアプリを管理者権限で実行
//=============================================================================
//  ShellExecuteEx 関数の使用例
//  コマンドプロンプトを管理者権限で起動
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LExeFile   : string;
  LParamText : string;
begin
  LExeFile   := 'Cmd.exe';
  LParamText := '/k cd /d c:\';

  RunExeFile(0, LExeFile, LParamText, 'runas', SW_SHOW);
end;




06_コマンドプロンプトやアプリを非表示で起動して実行


ShellExecuteEx 関数を使用して,コマンドプロンプトあるいは他のアプリケーションを非表示で起動するには,TShellExecuteInfo.nShow の値を SW_HIDE にします.
コマンド実行後にコマンドプロンプトを自動的に閉じるには,cmd.exe の起動オプションを /c にして起動します.



リスト10
コマンドプロンプトを非表示で起動してコマンドを実行する例
//=============================================================================
//  ShellExecuteEx 関数の使用例
//  コマンドプロンプトを非表示で起動する例
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LExeFile   : string;
  LParamText : string;
  LSaveFile  : string;
begin
  LSaveFile  := ExtractFilePath(Application.ExeName) + 'dir.txt';
  LExeFile   := 'Cmd.exe';
  LParamText := '/c dir c:\windows\system32>>' + LSaveFile;

  RunExeFile(0, LExeFile, LParamText, '', SW_HIDE);
end;