Tips その7


別プロセスを起動するには

通常は CreateProcess Win32 API 関数を使用します。

最も簡単な呼び出し方を次に示します。

function ExecuteProc(ExePath,                  // 実行可能ファイルのパス(通常 nil で良い)
                      CmdLine: PChar;          // コマンドライン
                      dwWait: Cardinal;        // 起動待ち時間
                      Console: Boolean;        // コンソールとして起動するか否か
                      var ProcHandle: THandle  // プロセスハンドル格納変数
                      ): Boolean;
var
  Rtn       : Cardinal;
  StartInfo : TStartupInfo;
  ProcInfo  : TProcessInformation;
begin

  Result:= False; // 戻り値を初期化
  ProcHandle:= 0; // プロセスハンドル初期化

  // プロセス起動情報設定
  ZeroMemory(@StartInfo, Sizeof(StartInfo));
  GetStartupInfo(StartInfo);
  with StartInfo do
  begin

    // サイズ設定
    cb:= Sizeof(StartInfo);

    // 表示抑制、標準ハンドルの変更を有効にする
    dwFlags:= STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;

    //コンソールモードの場合は非表示で起動
    if Console then wShowWindow:= SW_HIDE;

  end;

  // 外部プロセス起動
  if CreateProcess(ExePath,
                   CmdLine,
                   nil,
                   nil,
                   True,
                   0,
                   nil,
                   nil,
                   StartInfo,
                   ProcInfo) then
  begin
    // 外部プロセス起動待ち
    Rtn:= WaitForInputIdle(ProcInfo.hProcess, dwWait);
    if Rtn <> 0 then Exit; // 起動失敗時
    ProcHandle:= ProcInfo.hProcess; // プロセスハンドルを返す
    Result:= True;// 正常復帰(起動成功)
  end;

end;

この例では CmdLine に起動したいプログラム名(そのファイル名)と起動オプション(つまり、コマンドライン引数)を記述します。起動するプログラムがコンソールアプリである場合は、大抵その画面を非表示としたい(DOSプロンプトにしゃしゃり出て欲しくない)でしょうから、その場合は wShowWindow を SW_HIDE とするオプションもあります。

この他、Win3.1 時代からの互換性のために残してある WinExec() という API関数を使用することもできますが、これは将来のバージョンのWinodwsで削除される可能性がありますので、あまり使用しない方が良いようです。ただ、現バージョンのみ対応のアプリケーションで良いのあれば WinExec() の方が呼び出しは簡単です。


関連付けされたファイルを開くには

例えば、テキスト形式のファイルであれば、何らかのテキストエディタに関連付けられていて、テキストファイルをダブルクリックすれば、そのテキストエディタを明示的に指定しなくても自動的にそれで開かれます。これと同様のことをプログラムでやるには ShellExecute Win32 API関数を使用します。

この関数を利用するには、 ShellAPI ユニットを uses に追加する必要があります。

function ShellOpen(ParentHdl: THandle; OpenFile: String): Integer;
begin

  Result:= 0;// 戻り値初期化

  // ファイルの有無をチェック
  if not FileExists(OpenFile) then Exit;

  // ShellExecute 実行
  Result:= ShellExecute(ParentHdl,
                        'OPEN',
                        PChar(OpenFile),
                        nil,
                        nil,
                        SW_SHOW);

end;

ShellExecute の第1引数は 0 でも動きます。あと、第4引数は実行ディレクトリ名ですが、これは第3引数のファイル名でフルパスを指定すれば nil で良いです。


Windows をシャットダウンするには

ExitWindowsEx() Win32 API関数を使用します。Win95/98 系であれば、単にこの関数を呼ぶだけでシャットダウンできてしまうのですが、 WinNT/2000 系はアクセス権などの設定をしなければならないので、ちょっと面倒です。まぁ、やたらシャットダウンするものではない、ということなんでしょうけどね。

面倒ですが、やり方としては定型に近いので、次の例などを再利用できる形で使ってみてください。

function ExitWindowsSession(Operation: UINT): Integer;
var
  hToken : THandle;
  NewState : _TOKEN_PRIVILEGES;
  Luid : Int64;
  PrvState : _TOKEN_PRIVILEGES;
  PrvSize : Cardinal;
begin

  Result:= 0;// 戻り値設定

  // アクセストークン取得
  if OpenProcessToken(GetCurrentProcess,
                      TOKEN_QUERY or TOKEN_ADJUST_PRIVILEGES,
                      hToken) then
  begin
    // 特権名を識別
    LookupPrivilegeValue(nil,'SeShutdownPrivilege', Luid);

    // 特権設定
    NewState.PrivilegeCount:= Length(NewState.Privileges) + 1;
    NewState.Privileges[0].Luid:= Luid;
    NewState.Privileges[0].Attributes:= SE_PRIVILEGE_ENABLED;

    // アクセストークン特権の調整
    if AdjustTokenPrivileges(hToken,
                             False,
                             NewState,
                             Sizeof(PrvState),
                             PrvState,
                             PrvSize) then
    begin
      // セッション終了
      if not ExitWindowsEx(Operation, 0) then
         Result:= GetLastError;
    end else
    begin
      Result:= GetLastError;
    end;
  end else
  begin
    Result:= GetLastError;
  end;

end;

ふむ、定型ですな。


[ Delphi へ戻る ]