Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2008年05月03日] [更新 2017年04月04日] Delphi サンプルプログラム集
902_WMI プロセス ( アプリケーション ) の起動と終了
動作確認等 Windows 7 U64(SP1) + Delphi XE Pro
902_WMI_ProcessCreateTerminate.zip [4,106 KB] 2017年04月04日版 (EXE 同梱)



  • 2013年10月08日
  • イベント関係のサンプルは、後日、別の記事にすることにして削除
  • サービスアプリケーション関係のサンプルを追加
  • サンプルを全て OleVariant 型で扱うコードに変更




WMI を使用したプロセス ( アプリ ) 等の起動と終了


アプリケーションの起動と強制終了、サービスアプリケーションの起動や停止状態を変更するサンプルプログラムです。
本ページのサンプルでは、WMI 関係のオブジェクトを、多くの方が好んで使用する OleVariant 型でコーディングしています。したがって、WbemScripting_TLB.pas は使用していません。そのかわり、WMI オブジェクトを生成する際に ComObj が uses に必要となります。

[898_WMI イントロダクション]、[899_ネットワークコンピュータと WMI のメソッド] で、メソッド類の使用方法を説明しています。そこで、コメント類はかなり省略しています。





01_WMI によるアプリケーションの起動


Win32_Process クラスのメソッドを使用して、指定したアプリケーションを起動します。
アプリケーションのパス名等のパラメータは、Win32_ProcessStartup クラスのインスタンスのプロパティとして設定します。
アプリケーションのパス名は、原則的にフルパスで指定しますが、メモ帳のように、システム的にパスが通っている場合は省略できます。起動時の位置やサイズの指定は、起動するアプリケーション側がその指定を受け付けるようになっていないと機能しません。

起動に成功すると、プロセスID が取得できます。この値からウィンドウハンドル等を取得して、いろいろな操作が可能です。

このサンプルでは、ボタンクリックごとに WMI オブジェクトのインスタンスを生成、WMI サービスに接続していますが、実際にはアプリの起動時に実行すれば済みます。各々動作を独立させるために、このようにしているだけです。
必要と思われる部分だけをコピペして実行した結果、未定義のエラーの質問をされる方への、ささやかな対応策の 1 つと思ってください。


図1
設計時画面

以下は、実際の実行画面です。


図2
メモ帳を起動
  • 位置とサイズの指定は機能しない
図3
ワードを起動
  • 起動時に表示する文書を指定して起動
  • 位置とサイズの指定は機能しない
図4
添付の EXE を起動
  • 指定した位置とサイズで起動する

リスト1
WMI によるアプリケーションの起動
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

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

var
  Form1: TForm1;

implementation

uses ComObj, ShLwApi, ActiveX;

{$R *.dfm}

//-----------------------------------------------------------------------------
//  指定した拡張子に関連づけた実行ファイルのフルパス名を取得する関数
//  取得するのは拡張子の関連付けがレジストリに登録されているものの最初のもの
//
//  AssocQueryStringの使用にはusesにShLwApiが必要
//  OleCheckやWin32Checkを入れておくと例外を検出してくれる
//  OleCheckやWin32Checkの使用にはuuseにComObjが必要
//-----------------------------------------------------------------------------
function GetRelatedFullExePath(ExtName: String;
  DoubleQuote: Boolean=True; CmdParams: Boolean=False):string;
var
  Buf   : array [0..MAX_PAtH-1] of Char;
  dwOut : DWORD;
begin
  Result := '';

  FillChar(Buf, SizeOf(Buf), #0);
  dwOut := MAX_PATH;

  try
    //第2引数をASSOCSTR_EXECUTABLEにすれば"を含まないパス文字列となる
    if DoubleQuote then begin
      OleCheck(AssocQueryString(ASSOCF_NOTRUNCATE,
                                ASSOCSTR_COMMAND,
                                PChar(ExtName),
                                'open',
                                Buf,
                                @dwOut));
    end else begin
      OleCheck(AssocQueryString(ASSOCF_NOTRUNCATE,
                                ASSOCSTR_EXECUTABLE,
                                PChar(ExtName),
                                'open',
                                Buf,
                                @dwOut));
    end;
    Result := Buf;

    if Length(Result) = 0 then begin
      Result := '';
    end else begin
      if not CmdParams then begin
        //"(ダブルコーテーション)で囲まれている場合
        if Pos('" ', Result) > 0 then begin
          Result := Copy(Result, 1, Pos('" ', Result) + 1);
        end;
      end;
    end;
  except
  end;
end;

//=============================================================================
//  メモ帳を起動する
//  表示するファイルの指定なし
//  メモ帳はパスが通っているのでフルパスは不要
//  位置とサイズの指定は、実際には無効
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  objWMILocator : OleVariant;
  objWMIService : OleVariant;
  objProcess    : OleVariant;
  objConfig     : OleVariant;
  ProcessPath   : OleVariant;
  ProcessID     : Integer;
begin
  ProcessPath := 'Notepad.exe';

  ObjWMILocator := CreateOleObject('WbemScripting.SWbemLocator');
  ObjWMIService := ObjWMILocator.ConnectServer('', 'root\CIMV2');

  objConfig       := objWMIService.Get('Win32_ProcessStartup').SpawnInstance_;
  objConfig.X     := 100;
  objConfig.Y     := 100;
  objConfig.XSize := 800;
  objConfig.YSize := 500;
  objConfig.ShowWindow := SW_NORMAL;

  objProcess := objWMIService.Get('Win32_Process');
  objProcess.Create(ProcessPath, null, objConfig, ProcessID);
end;

//=============================================================================
//  ワードの文書をワードで開く
//  起動オプション(起動パラメータ)の区切りには空白が必要なことに注意
//  位置とサイズの指定は、実際には無効
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  ProcessPath   : OleVariant;
  objWMILocator : OleVariant;
  objWMIService : OleVariant;
  objProcess    : OleVariant;
  objConfig     : OleVariant;
  ProcessID     : Integer;
begin
  ProcessPath := GetRelatedFullExePath('.doc', True, False);
  ProcessPath := ProcessPath + ' /q '
                + AnsiQuotedStr(ExpandFileName('..\テスト文書.doc'), '"');

  ObjWMILocator := CreateOleObject('WbemScripting.SWbemLocator');
  ObjWMIService := ObjWMILocator.ConnectServer('', 'root\CIMV2');

  objConfig       := objWMIService.Get('Win32_ProcessStartup').SpawnInstance_;
  objConfig.X     := 100;
  objConfig.Y     := 100;
  objConfig.XSize := 800;
  objConfig.YSize := 500;
  objConfig.ShowWindow := SW_NORMAL;

  objProcess := objWMIService.Get('Win32_Process');
  objProcess.Create(ProcessPath, null, objConfig, ProcessID);
end;

//=============================================================================
//  添付のEXEを起動
//  TesForm.exeはDelphiで作成したもの
//  Positionプロパティの値をpoDefaultにある。他の値では位置とサイズの指定は無効
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  ProcessPath   : OleVariant;
  objWMILocator : OleVariant;
  objWMIService : OleVariant;
  objProcess    : OleVariant;
  objConfig     : OleVariant;
  ProcessID     : Integer;
begin
  ProcessPath := ExpandFileName('..\Test App\TesForm.exe');

  ObjWMILocator := CreateOleObject('WbemScripting.SWbemLocator');
  ObjWMIService := ObjWMILocator.ConnectServer('', 'root\CIMV2');

  objConfig       := objWMIService.Get('Win32_ProcessStartup').SpawnInstance_;
  objConfig.X     := Self.Left - 100;
  objConfig.Y     := Self.Top + Self.Height - 20;
  objConfig.XSize := 450;
  objConfig.YSize := 300;
  objConfig.ShowWindow := SW_NORMAL;

  objProcess := objWMIService.Get('Win32_Process');
  objProcess.Create(ProcessPath, null, objConfig, ProcessID);
end;

end.




02_WMI によるアプリケーションの強制終了


Win32_Process クラスのメソッドを使用して、指定したアプリケーションを強制終了します。

このサンプルでは、強制終了するアプリケーションを、ウィンドウハンドルやプロセスの ID 値ではなく、EXE のフルパスで指定しています。アプリケーションのパス名は、原則的にフルパスで指定しますが、メモ帳のように、システム的にパスが通っている場合は省略できます。

Win32_Process クラスでは、プロセスのいろいろな情報が取得できます。したがって、フルパス以外の条件で強制終了させることもできます。
Win32_Process クラスの Create メソッドで起動した場合、その引数の戻り値で、プロセスの ID 値が取得できますから、これを使用して、そのプロセスを強制終了できます。


図5
設計時画面

リスト2
WMI によるアプリケーションの強制終了
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

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

var
  Form1: TForm1;

implementation

uses ComObj, ActiveX;

{$R *.dfm}

{ TForm1 }

//=============================================================================
//  メモ帳を起動
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  ProcessPath   : OleVariant;
  objWMILocator : OleVariant;
  objWMIService : OleVariant;
  objProcess    : OleVariant;
  objConfig     : OleVariant;
  ProcessID     : Integer;
begin
  ProcessPath := 'Notepad.exe';

  ObjWMILocator := CreateOleObject('WbemScripting.SWbemLocator');
  ObjWMIService := ObjWMILocator.ConnectServer('', 'root\CIMV2');

  objConfig            := objWMIService.Get('Win32_ProcessStartup').SpawnInstance_;
  objConfig.ShowWindow := SW_NORMAL;

  objProcess := objWMIService.Get('Win32_Process');
  objProcess.Create(ProcessPath, null, objConfig, ProcessID);
end;

//=============================================================================
//  メモ帳を終了
//  全ての起動中のメモ帳を閉じる
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
const
  wbemFlagReturnImmediately = $00000010;
  wbemFlagForwardOnly = $00000020;
var
  ProcessPath   : OleVariant;
  objWMILocator : OleVariant;
  objWMIService : OleVariant;
  colItems      : OleVariant;
  colItem       : OleVariant;
  colEnum       : IEnumvariant;
  iValue        : LongWord;
begin
  ProcessPath := 'Notepad.exe';
  ProcessPath := QuotedStr(ExtractFileName(ProcessPath));

  ObjWMILocator := CreateOleObject('WbemScripting.SWbemLocator');
  ObjWMIService := ObjWMILocator.ConnectServer('', 'root\CIMV2');

  colItems    := objWMIService.ExecQuery(
                     'SELECT * FROM Win32_Process where name = '+ ProcessPath,
                     'WQL',
                     wbemFlagReturnImmediately);

  //コレクションを取得
  colEnum := IUnknown(colItems._NewEnum) as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下が各コレクションの操作コード
  //-------------------------------------------------------------------------

  //それを順番に取得
  while colEnum.Next(1, colItem, iValue) = 0 do begin
    //値がない場合はスキップ
    if iValue <= 0 then Break;
    if VarIsNull(colItem) then Continue;

    colItem.Terminate;
  end;
end;

end.




03_WMI による自分で起動したアプリだけの強制終了


Win32_Process クラスのメソッドを使用して、指定したアプリケーションを強制終了します。
前項のサンプルでは、指定したアプリ全てを強制終了しますが、本サンプルは、自分で起動したアプリケーションたけを強制終了しまた。ただし、最後に起動したアプリだけを強制終了します。

起動したアプリのプロセス ID の値をグローバル変数で保持し、その値を使用します。このプロセス ID の値は、最後に起動した値しか保持しません。したがって、最後に起動したアプリだけの強制終了となっています。


リスト3
最後に起動したアプリだけを強制終了する
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

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

var
  Form1: TForm1;

implementation

uses
  ComObj,
  ActiveX;

{$R *.dfm}

{ TForm1 }

//=============================================================================
//  メモ帳を起動
//  FProcessIDはグローバル変数で起動したメモ帳のプロセスIDの値
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  ProcessPath   : OleVariant;
  objWMILocator : OleVariant;
  objWMIService : OleVariant;
  objProcess    : OleVariant;
  objConfig     : OleVariant;
begin
  ProcessPath := 'Notepad.exe';

  ObjWMILocator := CreateOleObject('WbemScripting.SWbemLocator');
  ObjWMIService := ObjWMILocator.ConnectServer('', 'root\CIMV2');

  objConfig            := objWMIService.Get('Win32_ProcessStartup').SpawnInstance_;
  objConfig.ShowWindow := SW_NORMAL;

  objProcess := objWMIService.Get('Win32_Process');
  objProcess.Create(ProcessPath, null, objConfig, FProcessID);
end;

//=============================================================================
//  メモ帳を終了
//  上のボタンクリックで最後に起動したメモ帳だけを閉じる
//  プロセスIDの値はグローバル変数で、最後の値しか保存していない
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
const
  wbemFlagReturnImmediately = $00000010;
  wbemFlagForwardOnly = $00000020;
var
  objWMILocator : OleVariant;
  objWMIService : OleVariant;
  colItems      : OleVariant;
  colItem       : OleVariant;
  colEnum       : IEnumvariant;
  iValue        : LongWord;
begin
  ObjWMILocator := CreateOleObject('WbemScripting.SWbemLocator');
  ObjWMIService := ObjWMILocator.ConnectServer('', 'root\CIMV2');

  colItems := objWMIService.ExecQuery(
              'SELECT * FROM Win32_Process where ProcessId = '+ intToStr(FProcessID),
               'WQL',
               wbemFlagReturnImmediately);

  //コレクションを取得
  colEnum := IUnknown(colItems._NewEnum) as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下が各コレクションの操作コード
  //-------------------------------------------------------------------------

  //それを順番に取得
  while colEnum.Next(1, colItem, iValue) = 0 do begin
    //値がない場合はスキップ
    if iValue <= 0 then Break;
    if VarIsNull(colItem) then Continue;

    colItem.Terminate;
  end;
end;

end.




04_WMI によるサービスアプリケーションの起動や停止


Win32_Service クラスを使用して、サービスアプリケーションの一覧を取得します。
また、同じクラスのメソッドを使用して、取得したサービスアプリケーションの起動、停止等の操作を実行します。サービスの開始、停止等の操作は、管理者権限で実行しないと失敗します。
サービスアプリケーションのシステムへの登録や削除は、同じ Win32_Service クラスの Create メソッドや Delete メソッドを使用します。

このサンプルでも、ボタンクリックごとに WMI オブジェクトのインスタンスを生成、WMI サービスに接続していますが、実際にはアプリの起動時に実行すれば済みます。各々動作を独立させるために、このようにしているだけです。
必要と思われる部分だけをコピペして実行した結果、未定義のエラーの質問をされる方への、ささやかな対応策の 1 つと思ってください。


[備考]
システムの [サービス] の設定ダイアログは、コマンドライン (ファイル名を指定して実行のダイアログ) で services.msc を実行すると起動できます。



  • 図6
  • 設計時画面

  • 図7
  • 実行画面

下図は、起動、停止等の操作例です。
ここでは、lltdsvc サービスを開始して、自動起動に変更しています。


図8
変更前
  • [State] は Stopped (停止状態)
  • [StartMode] は Manual (手動)
図9
変更結果
  • [State] が Running (起動中)
  • [StartMode] が Auto (自動) になった

リスト4
WMI によるサービスアプリケーションの起動や停止
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Panel2: TPanel;
    Memo1: TMemo;
    ListView1: TListView;
    Splitter1: TSplitter;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure ListView1SelectItem(Sender: TObject; Item: TListItem;
      Selected: Boolean);
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
    LvTopItem : TListItem;
    LvSelItemIndex : Integer;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses ComObj, ActiveX;

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//  ListView1の先頭に表示するItemと選択Itemの設定
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  LvTopItem      := nil;
  LvSelItemIndex := -1;
end;

//=============================================================================
//  サービスアプリケーションの一覧取得
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
const
  wbemFlagReturnImmediately = $00000010;
  wbemFlagForwardOnly = $00000020;
var
  objWMILocator : OleVariant;
  objWMIService : OleVariant;
  colItems      : OleVariant;
  colItem       : OleVariant;
  colEnum       : IEnumvariant;
  iValue        : LongWord;
  AItem         : TListItem;
begin
  ObjWMILocator := CreateOleObject('WbemScripting.SWbemLocator');
  ObjWMIService := ObjWMILocator.ConnectServer('localhost', 'root\CIMV2');

  colItems    := objWMIService.ExecQuery(
                     'SELECT * FROM Win32_Service',
                     'WQL',
                     wbemFlagReturnImmediately or wbemFlagForwardOnly);

  //コレクションを取得
  colEnum := IUnknown(colItems._NewEnum) as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下が各コレクションの操作コード
  //-------------------------------------------------------------------------

  //それを順番に取得して表示
  ListView1.Items.Clear;
  ListView1.Items.BeginUpdate;

  while colEnum.Next(1, colItem, iValue) = 0 do begin
    AItem := ListView1.Items.Add;
    AItem.Caption := VarToStr(colItem.Name);
    AItem.SubItems.Add(VarToStr(colItem.State));
    AItem.SubItems.Add(VarToStr(colItem.StartMode));
    AItem.SubItems.Add(VarToStr(colItem.PathName));

    colItem := Unassigned;
  end;
  ListView1.Items.EndUpdate;

  if Sender = nil then begin
    ListView1.ItemIndex := LvSelItemIndex;
    //現在ListView1の最上行に表示するItemを設定
    if LvTopItem <> nil then begin
      if ListView1.TopItem <> LvTopItem then begin
        ListView1.Scroll(0, LvTopItem.Top - ListView1.TopItem.Top);
      end;
    end;
  end;
end;

//=============================================================================
//  サービスアプリケーションの停止
//  実行には管理者権限が必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
const
  wbemFlagReturnImmediately = $00000010;
  wbemFlagForwardOnly = $00000020;
var
  ServiceName   : String;
  objWMILocator : OleVariant;
  objWMIService : OleVariant;
  colItems      : OleVariant;
  colItem       : OleVariant;
  colEnum       : IEnumvariant;
  iValue        : LongWord;
begin
  if ListView1.ItemIndex < 0 then exit;
  if ListView1.SelCount > 1  then exit;

  LvTopItem      := ListView1.TopItem;
  LvSelItemIndex := ListView1.Selected.Index;

  ServiceName := ListView1.Selected.Caption;
  ServiceName := QuotedStr(ExtractFileName(ServiceName));

  ObjWMILocator := CreateOleObject('WbemScripting.SWbemLocator');
  ObjWMIService := ObjWMILocator.ConnectServer('localhost', 'root\CIMV2');

  colItems    := objWMIService.ExecQuery(
                     'SELECT * FROM Win32_Service where name = ' + ServiceName,
                     'WQL',
                     wbemFlagReturnImmediately or wbemFlagForwardOnly);

  //コレクションを取得
  colEnum := IUnknown(colItems._NewEnum) as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下が各コレクションの操作コード
  //-------------------------------------------------------------------------

  //それを順番に取得
  while colEnum.Next(1, colItem, iValue) = 0 do begin
    colItem.StopService;
    colItem := Unassigned;
  end;

  Button1Click(nil);
end;

//=============================================================================
//  サービスアプリケーションの開始
//  実行には管理者権限が必要
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
const
  wbemFlagReturnImmediately = $00000010;
  wbemFlagForwardOnly = $00000020;
var
  ServiceName   : String;
  objWMILocator : OleVariant;
  objWMIService : OleVariant;
  colItems      : OleVariant;
  colItem       : OleVariant;
  colEnum       : IEnumvariant;
  iValue        : LongWord;
begin
  if ListView1.ItemIndex < 0 then exit;
  if ListView1.SelCount > 1  then exit;

  LvTopItem      := ListView1.TopItem;
  LvSelItemIndex := ListView1.Selected.Index;

  ServiceName := ListView1.Selected.Caption;
  ServiceName := QuotedStr(ExtractFileName(ServiceName));

  ObjWMILocator := CreateOleObject('WbemScripting.SWbemLocator');
  ObjWMIService := ObjWMILocator.ConnectServer('localhost', 'root\CIMV2');

  colItems    := objWMIService.ExecQuery(
                     'SELECT * FROM Win32_Service where name = ' + ServiceName,
                     'WQL',
                     wbemFlagReturnImmediately or wbemFlagForwardOnly);

  //コレクションを取得
  colEnum := IUnknown(colItems._NewEnum) as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下が各コレクションの操作コード
  //-------------------------------------------------------------------------

  //それを順番に取得
  while colEnum.Next(1, colItem, iValue) = 0 do begin
    colItem.StartService;
    colItem := Unassigned;
  end;

  Button1Click(nil);
end;

//=============================================================================
//  サービスアプリケーションを手動開始にする
//  実行には管理者権限が必要
//=============================================================================
procedure TForm1.Button4Click(Sender: TObject);
const
  wbemFlagReturnImmediately = $00000010;
  wbemFlagForwardOnly = $00000020;
var
  ServiceName   : String;
  objWMILocator : OleVariant;
  objWMIService : OleVariant;
  colItems      : OleVariant;
  colItem       : OleVariant;
  colEnum       : IEnumvariant;
  iValue        : LongWord;
begin
  if ListView1.ItemIndex < 0 then exit;
  if ListView1.SelCount > 1  then exit;

  LvTopItem      := ListView1.TopItem;
  LvSelItemIndex := ListView1.Selected.Index;

  ServiceName := ListView1.Selected.Caption;
  ServiceName := QuotedStr(ExtractFileName(ServiceName));

  ObjWMILocator := CreateOleObject('WbemScripting.SWbemLocator');
  ObjWMIService := ObjWMILocator.ConnectServer('localhost', 'root\CIMV2');

  colItems    := objWMIService.ExecQuery(
                     'SELECT * FROM Win32_Service where name = ' + ServiceName,
                     'WQL',
                     wbemFlagReturnImmediately or wbemFlagForwardOnly);

  //コレクションを取得
  colEnum := IUnknown(colItems._NewEnum) as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下が各コレクションの操作コード
  //-------------------------------------------------------------------------

  //それを順番に取得
  while colEnum.Next(1, colItem, iValue) = 0 do begin
    colItem.ChangeStartMode('Manual');
    colItem := Unassigned;
  end;

  Button1Click(nil);
end;

//=============================================================================
//  サービスアプリケーションを自動開始にする
//  実行には管理者権限が必要
//=============================================================================
procedure TForm1.Button5Click(Sender: TObject);
const
  wbemFlagReturnImmediately = $00000010;
  wbemFlagForwardOnly = $00000020;
var
  ServiceName   : String;
  objWMILocator : OleVariant;
  objWMIService : OleVariant;
  colItems      : OleVariant;
  colItem       : OleVariant;
  colEnum       : IEnumvariant;
  iValue        : LongWord;
begin
  if ListView1.ItemIndex < 0 then exit;
  if ListView1.SelCount > 1  then exit;

  LvTopItem      := ListView1.TopItem;
  LvSelItemIndex := ListView1.Selected.Index;

  ServiceName := ListView1.Selected.Caption;
  ServiceName := QuotedStr(ExtractFileName(ServiceName));

  ObjWMILocator := CreateOleObject('WbemScripting.SWbemLocator');
  ObjWMIService := ObjWMILocator.ConnectServer('localhost', 'root\CIMV2');

  colItems    := objWMIService.ExecQuery(
                     'SELECT * FROM Win32_Service where name = ' + ServiceName,
                     'WQL',
                     wbemFlagReturnImmediately or wbemFlagForwardOnly);

  //コレクションを取得
  colEnum := IUnknown(colItems._NewEnum) as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下が各コレクションの操作コード
  //-------------------------------------------------------------------------

  //それを順番に取得
  while colEnum.Next(1, colItem, iValue) = 0 do begin
    colItem.ChangeStartMode('Automatic');
    colItem := Unassigned;
  end;

  Button1Click(nil);
end;

//=============================================================================
//  ListView1のOnSelectItemイベント処理
//  選択したサービスのDescriptionプロパティの値をMemo1に表示
//=============================================================================
procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
const
  wbemFlagReturnImmediately = $00000010;
  wbemFlagForwardOnly = $00000020;
var
  ServiceName   : String;
  objWMILocator : OleVariant;
  objWMIService : OleVariant;
  colItems      : OleVariant;
  colItem       : OleVariant;
  colEnum       : IEnumvariant;
  iValue        : LongWord;
begin
  if ListView1.ItemIndex < 0 then exit;
  if ListView1.SelCount > 1  then exit;

  ServiceName := ListView1.Selected.Caption;
  ServiceName := QuotedStr(ExtractFileName(ServiceName));

  ObjWMILocator := CreateOleObject('WbemScripting.SWbemLocator');
  ObjWMIService := ObjWMILocator.ConnectServer('localhost', 'root\CIMV2');

  colItems    := objWMIService.ExecQuery(
                     'SELECT * FROM Win32_Service where name = ' + ServiceName,
                     'WQL',
                     wbemFlagReturnImmediately or wbemFlagForwardOnly);

  //コレクションを取得
  colEnum := IUnknown(colItems._NewEnum) as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下が各コレクションの操作コード
  //-------------------------------------------------------------------------

  //それを順番に取得
  while colEnum.Next(1, colItem, iValue) = 0 do begin
    Memo1.Lines.Text := VarToStr(colItem.Description);
    colItem := Unassigned;
  end;
end;

end.


上のコードでは、サービスアプリケーションの状態を変更した後、再度一覧を取得しています。
TListView の最上行に表示する Item を制御する参考としてそうしてみました。
実際には、再度一覧を取得する必要はありません。該当サービスの状態だけを取得して、ListView1 の SubItem の値だけを更新するだけで済みます。

ただし、サービスアプリケーションによっては、関係する別のサービスアプリケーションの起動や停止が必要な場合があります。この意味では、一覧の再取得の方が無難かも知れません。
また、WMI のオブジェクトはグローバル変数にした方がコードの見通しがいいかも知れません。

TListView の Caption の表示を、コマンド services.msc を実行した時の [サービス] のダイアログの表示と同じにするには、DisplayName プロパティの値を表示します。上のコードは Name プロパティを表示しています。Caption に表示するプロパティを変更したら、ExecQuery で実行するクエリーの条件文も変更する必要があります。また、表示の順がアルファベット順にならなくなります。ソートも必要となります。

下図はその変更をした結果です。上のコードを実行した時に AppInfo と表示されていたサービスの名前が Appliction Infomation となっています。

  • 図10
  • TListView の Caption の値を DisplayName にした結果