Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2021年10月08日] [更新 2021年10月11日] Delphi サンプルプログラム集
324_特定の UWP アプリが起動中かを確認
動作確認等 Windows 10 ビルド 19042 + Delphi XE5(UP2) Pro VCL-32
324_CheckRun_UWPApp.zip [4.3 MB] 2021年10月11日版 (EXE 同梱)







特定の UWP アプリが起動中かを確認


デスクトップアプリでは,FindWindow 関数を使用して,ウィンドウのクラス名で目的のアプリのウィンドウが起動しているこを確認できます.Windows 10 の UWP アプリではこの方法は利用できません.Windows 10 の UWP アプリのウィンドウのクラス名は全て同じです.クラス名ではアプリを判定できません.

下に示すコードは,ウィンドウのタイトルでアプリを判定する例です.ペイント 3D を起動して [起動チェック] ボタンをクリックするとペイント 3D アプリが起動ていることが確認できます.ところが,ペイント 3D アプリを終了しても起動中になることがあります.Windows 10 の UWP アプリにはバックグラウンドで実行する機能があり,デスクトップに表示しているウィンドウを閉じても,バックグラウンドでそのアプリが実行されることがあります.その結果,次回の起動が) か高速にります (正確には,既に起動してバックグラウンドで実行されているのですが).このように,Windows 10 の UWP アプリは「親切」な仕様になっています.



図1
ペイント 3D が実行中かを確認
  • ウィンドウのタイトルで判定
  • ペイント 3D を閉じてもこの結果となる

リスト1
ウィンドウのタイトルで,アプリが実行中かを判定するコード
//=============================================================================
//  特定の UWP アプリが起動しているかを確認
//  FindWindow 関数でウィンドウのタイトルを検索する方法
//  デスクトップ画面に表示されていなくても「起動中」になることがある
//  これは正確には正しい
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LTargetWnd : HWND;
  LWndTitle  : string;
  LText  : string;
begin
  LWndTitle  := 'タイトルなし ' + #$200E + '- ペイント 3D';
  // 以下でもバックグラウンドて実行されている場合,結果は同じ
  // LWndTitle  := 'ペイント 3D';

  LTargetWnd := FindWindow(nil, PChar(LWndTitle));

  if LTargetWnd <> 0 then begin
    LText :=  'ペイント 3D は起動しています。';
    MessageBox(Handle, PChar(LText), '情報', MB_TOPMOST or MB_ICONINFORMATION);
  end else begin
    LText :=  'ペイント 3D は起動していません。';
    MessageBox(Handle, PChar(LText), '情報', MB_TOPMOST or MB_ICONINFORMATION);
  end;
end;


[備考 1]
Windows 10 の UWP アプリは,バックグラウンドで起動して実行されるのですから,このサンプルでは起動中のアプリの検出ができているわけです.本ページの主題は,正確に言うと「起動してウインドウがデスクトップに表示されている UWP アプリ」の確認です.

[備考 2]
ペイント 3D のウィンドウのタイトルには Shift_JIS にはないコードポイントがありますが,これはアプリによって異なります.Chromium 版の Microsoft Edge では #$200B です.

[備考 3]
ペイント 3D は,2017年10月17日の Windows 10 Fall Creators Update で搭載されたアプリです.初期の Windows 10 にはありません.




01_特定の AppUserModelId の UWP アプリが起動中かを確認


デスクトップのアプリケーションを識別するのは EXE 名です.Windows 10 の UWP アプリを識別するのは,アプリケーション識別子である AppUserModelId の値です.この AppUserModelId の値を使用すると,特定の UWP アプリが起動していかを調べることが可能です.

このサンプルでは,EnumWindows 関数の引数に AppUserModelId の値を渡します.EnumWindows のコールバック関数内では,ウィンドウハンドルから AppUserModelId の値を取得して,引数の値と一致したら,引数にそのウインドウのハンドルの値を文字列にして返します.このウィンドウハンドルは,対象のアプリの操作に利用できます.
コールバック関数内では,DwmGetWindowAttribute 関数を使用して,待機中またはバックグラウンドで実行されているウィンドウを検索の対象外としています.

このサンプルは UWP アプリ専用です.特定の EXE 名のアプリが起動しているを確認する方法については,以下の最後のリンクの記事を参考にしてください.



図2
起動中の場合
  • ウィンドウハンドルを検出して判定

リスト2
特定の AppUserModelId の UWP アプリが起動中かを確認
unit Unit1;

interface

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

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

  function EnumWindowProc(hWindow: HWND; lPara: LPARAM): Boolean; stdcall;
  function GetWindowClassName(hWindow: HWND): string;

var
  Form1: TForm1;

implementation

uses
  Winapi.Dwmapi,
  Winapi.ShellAPI,
  Winapi.ActiveX,
  Winapi.propSys,
  Winapi.PropKey;

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//  テスト用の AppUserModelId の値をセット
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  // ペイント 3D
  Edit1.Text:= 'Microsoft.MSPaint_8wekyb3d8bbwe!Microsoft.MSPaint';
end;

//=============================================================================
//  特定の AppUserModelId の UWP アプリが起動しているかを確認
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LAppId     : string;
  LArgWnd    : string;
  LTargetWnd : HWND;
  LText     : string;
begin
  LAppId  := Trim(Edit1.Text);
  LArgWnd := LAppId;

  EnumWindows(@EnumWindowProc, LPARAM(@LArgWnd));

  LTargetWnd := StrToIntDef(LArgWnd, 0);
  if LTargetWnd <> 0 then begin
    LText :=  'ペイント 3D は起動しています。';
    MessageBox(Handle, PChar(LText), '情報', MB_TOPMOST or MB_ICONINFORMATION);
  end else begin
    LText :=  'ペイント 3D は起動していません。';
    MessageBox(Handle, PChar(LText), '情報', MB_TOPMOST or MB_ICONINFORMATION);
  end;
end;

//=============================================================================
//  アプリを起動
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LShellPath : string;
begin
  LShellPath := 'shell:AppsFolder\' + Trim(Edit1.Text);
  ShellExecute(0, '', PChar(LShellPath), nil, nil, SW_SHOW);
end;

//-----------------------------------------------------------------------------
//  EnumWindows のコールバック関数
//  引数 (lPara - AppUserModelId の値) と同じ UWP アプリが起動しているかをチェック
//  検出したら引数 (lPara) にそのウィンドウハンドルの値を文字列にして渡す
//-----------------------------------------------------------------------------
function EnumWindowProc(hWindow: HWND; lPara: LPARAM): Boolean; stdcall;
const
  UWP_FRAMEWND  = 'ApplicationFrameWindow';
  DWMWA_CLOAKED = 14;
var
  LIsUWPApp  : Boolean;
  LCloaked   : BOOL;
  LPropStore : IPropertyStore;
  LPropVar   : TPropVariant;
  LAppID     : string;
begin
  Result := True;

  if GetWindow(hWindow, GW_OWNER) <> 0 then exit;
  if not IsWindowVisible(hWindow) then exit;

  // 待機中またはバックグラウンドのウィンドウは対象外
  DwmGetWindowAttribute(hWindow, DWMWA_CLOAKED, @LCloaked, SizeOf(LCloaked));
  if LCloaked then Exit;


  // クラス名 ApplicationFrameWindow のウインドウが UWP アプリ
  LIsUWPApp := GetWindowClassName(hWindow) = UWP_FRAMEWND;

  if LIsUWPApp then begin
    // ウィンドウハンドルの値から AppUserModelId の値を取得
    if SHGetPropertyStoreForWindow(hWindow,
                                   IID_IPropertyStore,
                                   Pointer(LPropStore)) <> S_OK then Exit;
    if LPropStore.GetValue(PKEY_AppUserModel_ID, LPropVar) <> S_OK then Exit;
    LAppID := LPropVar.bstrVal;
    if SameText(LAppID, PString(lPara)^) then begin
      PString(lPara)^ := IntToStr(hWindow);
      Result := False;
    end;
  end;
end;

//-----------------------------------------------------------------------------
//  ウィンドウのクラス名を取得する関数
//-----------------------------------------------------------------------------
function GetWindowClassName(hWindow: HWND): string;
var
  LBuff : array [0..MAX_PATH - 1] of Char;
begin
  Result := '';
  FillChar(LBuff, SizeOf(LBuff), #0);
  if (GetClassName(hWindow, @LBuff, MAX_PATH) > 0) then begin
    Result := LBuff;
  end;
end;

end.


上のサンプルでは,ペイント 3D のウィンドウハンドルを取得しいます.したがって,以下のコードを実行すれば,ペイント 3D のウィンドウの表示位置とサイズを変更できます.

    SetWindowPos(LTargetWnd,
                 0,
                 200, // 右端 X 座標
                 0,   // 上端 Y 座標
                 500, //
                 600, // 高さ
                 SWP_NOZORDER);




02_プロセスのハンドルと GetAppUserModelId 関数


Windows API には,起動中のプロセスのハンドルから AppUserModelId の値やパッケージ名を取得する関数類があります.例えば以下のような関数です.本サンプルは,GetApplicationUserModelId 関数を使用して,起動中の UWP アプリを判定する例です.

  // 以下の関数類におけるプロセスのハンドルとは
  // クラス名が Windows.UI.Core.CoreWindow のウィンドウのプロセスハンドル

  // プロセスのハンドルから AppUserModelId の値を取得
  function GetApplicationUserModelId(hProcess: THandle; Size: PDWORD;
    AppId: PWideChar): DWORD; stdcall; external 'kernelBase.dll';

  // プロセスのハンドルからパッケージ名 (フルパッケージ名) 値を取得
  // バージョン番号があるパッケージ名
  function GetPackageFullName(hProcess: THANDLE; Size: PDWORD; Path: PWideChar):
    DWORD; stdcall; external 'kernel32.dll';

  // プロセスのハンドルからパッケージのファミリー名を取得
  // これをパッケージ名と言うこともある
  function GetPackageFamilyName(hProcess: THANDLE; Size: PDWORD; Path: PWideChar):
    DWORD; stdcall; external 'kernel32.dll';


本サンプルでは,フォームに配置した TMemo に取得した値を表示します.
最初の値は GetApplicationUserModelId 関数で取得した以下の AppUserModelId の値です.この値とコールバック関数の引数 (lPara) の値が一致すれば,その時のウィンドウハンドルの値が検索対象のアプリのウィンドウハンドルの値です.

Microsoft.MSPaint_8wekyb3d8bbwe!Microsoft.MSPaint


その次の値は,そのウィンドウのプロセスのハンドルを取得して,QueryFullProcessImageNameW 関数でフルパスを取得した結果です.
UWP アプリの場合,全てこの値になります.

C:\Windows\System32\ApplicationFrameHost.exe


以下は最後の値です.これは,検索対象の UWP アプリの EXE のフルパスです.この EXE ファイルは,インストール先のフォルダ内にあります.UWP アプリは,この EXE からは起動でききません.インストール先のパッケージ名は,UWP アプリのバージョンが変わると変わる可能性があります.

C:\Program Files\WindowsApps\Microsoft.MSPaint_6.2105.4017.0_x64__8wekyb3d8bbwe\PaintStudio.View.exe


UWP アプリのトップレベルのウィンドウのクラス名は ApplicationFrameWindow です.このウィンドウの階層直下に,クラス名が Windows.UI.Core.CoreWindow まウィンドウがあります.GetApplicationUserModelId 関数は,そのウィンドウのプロセスハンドルの値を使用して取得します.クラス名が ApplicationFrameWindow のウィンドウのプロセスハンドルからは取得できません.EXE のフルパスも同じです.

UWP アプリのウィンドウが最小化状態になると,クラス名が Windows.UI.Core.CoreWindow のウィンドウは切り離されて独立したトップレベルのウィンドウになります.このウィンドウは,バックグラウンドのプロセスとして実行されます.したがって,このサンプルは,対象の UWP アプリが最小化状態の時は,起動していない判定となります.



図3
実行時の画面

リスト3
プロセスのハンドルから AppUserModelId の値や UWP アプリの EXE のフルパスを取得
unit Unit1;

interface

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

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


  function GetApplicationUserModelId(hProcess: THandle; Size: PDWORD;
    AppId: PWideChar): DWORD; stdcall; external 'kernelBase.dll';
      function QueryFullProcessImageNameW(Process: THandle; Flags: DWORD; 
        Buffer: PWideChar; Size: PDWORD): DWORD; stdcall; external 'kernel32.dll';

  function EnumWindowProc(hWindow: HWND; lPara: LPARAM): Boolean; stdcall;

var
  Form1: TForm1;

implementation

uses
  Winapi.Dwmapi,
  Winapi.ShellAPI,
  Winapi.ActiveX;

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//  テスト用の AppUserModelId の値をセット
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  // ペイント 3D
  Edit1.Text:= 'Microsoft.MSPaint_8wekyb3d8bbwe!Microsoft.MSPaint';
end;

//=============================================================================
//  特定の AppUserModelId の UWP アプリが起動しているかを確認
//  プロセスのハンドルと GetApplicationUserModelId 関数の動作確認用
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LAppId     : string;
  LArgAppId  : string;
  LTargetWnd : HWND;
  LText     : string;
begin
  Memo1.Lines.Clear;

  LAppId    := Trim(Edit1.Text);
  LArgAppId := LAppId;

  EnumWindows(@EnumWindowProc, LPARAM(@LArgAppId));

  LTargetWnd := StrToIntDef(LArgAppId, 0);
  if LTargetWnd = 0 then begin
    Memo1.Lines.Add('起動していないか最小化状態です。');
  end;
end;

//=============================================================================
//  アプリを起動
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LShellPath : string;
begin
  LShellPath := 'shell:AppsFolder\' + Trim(Edit1.Text);
  ShellExecute(0, '', PChar(LShellPath), nil, nil, SW_SHOW);
end;

//-----------------------------------------------------------------------------
//  EnumWindows のコールバック関数
//  引数 (lPara - AppUserModelId の値) と同じ UWP アプリが起動しているかをチェック
//  検出したら引数 (lPara) にそのウィンドウハンドルの値を文字列にして渡す
//-----------------------------------------------------------------------------
function EnumWindowProc(hWindow: HWND; lPara: LPARAM): Boolean; stdcall;
const
  UWP_FRAMEWND  = 'ApplicationFrameWindow';
  UWP_COREWND   = 'Windows.UI.Core.CoreWindow';
  DWMWA_CLOAKED = 14;
  PROCESS_QUERY_LIMITED_INFORMATION = $1000;
var
  LCloaked   : BOOL;
  LCoreWnd   : HWND;
  LProcessID : DWORD;
  LhProcess  : THandle;
  LBuffer    : array [0..MAX_PATH - 1] of Char;
  LSTR_SIZE  : DWORD;
  LResText   : string;
  LExePath1  : string;
  LExePath2  : string;
begin
  Result := True;

  if GetWindow(hWindow, GW_OWNER) <> 0 then exit;
  if not IsWindowVisible(hWindow) then exit;

  // 待機中またはバックグラウンドのウィンドウは対象外
  DwmGetWindowAttribute(hWindow, DWMWA_CLOAKED, @LCloaked, SizeOf(LCloaked));
  if LCloaked then Exit;


  // ウィンドウのクラス名が ApplicationFrameWindow の プロセスIDを取得
  // その値からプロセスのオープンハンドル取得
  // そのプロセスハンドルから EXE のフルパスを取得
  // 一般のデスクトップアプリは,これで EXE のフルパスが取得できる

  GetWindowThreadProcessId(hWindow, @LProcessID);
  LhProcess := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, LProcessID);
  try
    // EXE のフルパスを取得
    FillChar(LBuffer, SizeOf(LBuffer), #0);
    LSTR_SIZE := Length(LBuffer);
    LExePath1:='';
    if QueryFullProcessImageNameW(LhProcess,
                                  0,
                                  @LBuffer[0],
                                  @LSTR_SIZE) = 0 then Exit;
    LExePath1 := LBuffer;
  finally
    CloseHandle(LhProcess);
  end;

  // ウィンドウのクラス名が Windows.UI.Core.CoreWindow のウィンドウハンドルを取得
  // このウィンドはクラス名が ApplicationFrameWindow のウィンドウの階層下にある
  // このウィンドウは最小化状態の時は  ApplicationFrameWindow の階層下に存在しない

  LCoreWnd := FindWindowEx(hWindow, 0, UWP_COREWND, nil);
  if LCoreWnd = 0 then Exit;


  // ウィンドウのクラス名が Windows.UI.Core.CoreWindow の プロセスIDを取得
  // その値からプロセスのオープンハンドル取得
  // そのプロセスハンドルから AppUserModelId の値と EXE のフルパスを取得

  GetWindowThreadProcessId(LCoreWnd, @LProcessID);
  LhProcess := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, LProcessID);
  try
    // AppUserModelId の値を取得
    LSTR_SIZE := SizeOf(LBuffer);
    FillChar(LBuffer, SizeOf(LBuffer), #0);
    GetApplicationUserModelId(LhProcess, @LSTR_SIZE, @LBuffer);
    LResText := LBuffer;

    // 取得した値と引数 (lPara) の値が同じなら検索終了
    if SameText(LResText, PString(lPara)^) then begin
      PString(lPara)^ := IntToStr(hWindow);
      Result := False;

      // EXE のフルパスを取得
      FillChar(LBuffer, SizeOf(LBuffer), #0);
      LSTR_SIZE := Length(LBuffer);
      LExePath2:='';
      if QueryFullProcessImageNameW(LhProcess,
                                    0,
                                    @LBuffer[0],
                                    @LSTR_SIZE) = 0 then Exit;
      LExePath2 := LBuffer;

      // 取得した値を表示                    ]
      Form1.Memo1.Lines.Add(LResText);
      Form1.Memo1.Lines.Add(LExePath1);
      Form1.Memo1.Lines.Add(LExePath2);
    end;
  finally
    CloseHandle(LhProcess);
  end;
end;

end.




03_AppUserModelId の値からアプリ名を取得


SHGetFileInfo 関数を使用すると,AppUserModelId の値からアプリ名を取得できます.


図4
ペイント 3D の AppuserModelId の値からアプリ名を取得した結果

リスト4
AppUserModelId の値からアプリ名を取得.SHGetFileInfo 関数を使用
unit Unit1;

interface

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

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

  function AppUserModelIdToAppName(const AppId: string): string;

var
  Form1: TForm1;

implementation

uses
  Winapi.ShellAPI,
  Winapi.ActiveX,
  Winapi.ShlObj;

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//  テスト用の AppUserModelId の値をセット
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  // ペイント 3D
  Edit1.Text:= 'Microsoft.MSPaint_8wekyb3d8bbwe!Microsoft.MSPaint';

  // メモ帳
  // Edit1.Text := '{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\notepad.exe';
end;

//=============================================================================
//  AppUserModelId の値からアプリ名を取得
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LAppId   : string;
  LAppName : string;
  LText  : string;
begin
  LAppId  := Trim(Edit1.Text);

  LAppName := AppUserModelIdToAppName(LAppId);
  if LAppName = '' then begin
    LText := '該当するアプリが見つかりませんでした。';
    MessageBox(Handle, PChar(LText), 'アプリ名', MB_TOPMOST or MB_ICONWARNING);
  end else begin
    LText := 'アプリ名' + sLineBreak + LAppName;
    MessageBox(Handle, PChar(LText), 'アプリ名', MB_TOPMOST or MB_ICONINFORMATION);
  end;
end;

//=============================================================================
//  アプリを起動
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LShellPath : string;
begin
  LShellPath := 'shell:AppsFolder\' + Trim(Edit1.Text);
  ShellExecute(0, '', PChar(LShellPath), nil, nil, SW_SHOW);
end;

//-----------------------------------------------------------------------------
//  AppUserModelId の値からアプリ名を取得する関数
//  SHGetFileInfo 関数を使用
//-----------------------------------------------------------------------------
function AppUserModelIdToAppName(const AppId: string): string;
var
  LShellPath : string;
  LFileInfo  : TSHFileInfo;
  LpidlAppId : PItemIDList;
begin
  Result := '';
  LShellPath := 'shell:AppsFolder\' + AppId;

  LpidlAppId := ILCreateFromPath(PChar(LShellPath));
  if ILIsEmpty(LpidlAppId) then Exit;

  SHGetFileInfo(Pointer(LpidlAppId),
                0,
                LFileInfo,
                SizeOf(TSHFileInfo),
                SHGFI_PIDL or SHGFI_DISPLAYNAME);
  CoTaskMemFree(LpidlAppId);
  Result := LFileInfo.szDisplayName;
end;

end.


以下のリンクの記事のサンプルのように,IShellItem インターフェイスを使用しても,AppUserModelId の値からアプリ名を取得することができます.


リスト5
AppUserModelId の値からアプリ名を取得.IShellItem を使用
unit Unit1;

interface

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

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

  function AppUserModelIdToAppName(const AppId: string): string;

var
  Form1: TForm1;

implementation

uses
  Winapi.ShellAPI,
  Winapi.ActiveX,
  Winapi.ShlObj;

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//  テスト用の AppUserModelId の値をセット
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  // ペイント 3D
  Edit1.Text:= 'Microsoft.MSPaint_8wekyb3d8bbwe!Microsoft.MSPaint';

  // メモ帳
  // Edit1.Text := '{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\notepad.exe';
end;

//=============================================================================
//  AppUserModelId の値からアプリ名を取得
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LAppId   : string;
  LAppName : string;
  LText  : string;
begin
  LAppId  := Trim(Edit1.Text);

  LAppName := AppUserModelIdToAppName(LAppId);
  if LAppName = '' then begin
    LText := '該当するアプリが見つかりませんでした。';
    MessageBox(Handle, PChar(LText), 'アプリ名', MB_TOPMOST or MB_ICONWARNING);
  end else begin
    LText := 'アプリ名' + sLineBreak + LAppName;
    MessageBox(Handle, PChar(LText), 'アプリ名', MB_TOPMOST or MB_ICONINFORMATION);
  end;
end;

//=============================================================================
//  アプリを起動
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LShellPath : string;
begin
  LShellPath := 'shell:AppsFolder\' + Trim(Edit1.Text);
  ShellExecute(0, '', PChar(LShellPath), nil, nil, SW_SHOW);
end;

//-----------------------------------------------------------------------------
//  AppUserModelId の値からアプリ名を取得する関数
//  IShellItem を使用
//-----------------------------------------------------------------------------
function AppUserModelIdToAppName(const AppId: string): string;
var
  LAppId     : string;
  LpidlAppID : PItemIDList;
  LShItem    : IShellItem;
  LAppIdName : PWideChar;
begin
  Result := '';
  LAppId  := 'shell:AppsFolder\' + AppId;

  LpidlAppID := ILCreateFromPath(PChar(LAppId));
  if ILIsEmpty(LpidlAppID) then Exit;

  // 項目識別子の IShellItem オブジェクトを取得してその表示名を取得
  SHCreateItemFromIDList(LpidlAppID, IShellItem, LShItem);
  LShItem.GetDisplayName(SIGDN_NORMALDISPLAY, LAppIdName);

  LShItem := nil;
  CoTaskMemFree(LpidlAppID);
  Result := LAppIdName;
end;

end.




04_[ バックラウンドで実行 ] の機能を無効にする方法


[設定] アプリで,UWP アプリの [バックグラウンドで実行] の機能をアプリ単位で設定できます.次のコマンドを実行して設定画面を表示します.

ms-settings:privacy-backgroundapps


下図のように,対象のアプリのスイッチをオフにします.コンピュータを再起動して,本ページの最初のサンプルを実行すれば,起動したペイント 3D を閉じると [起動していません] と表示するようになります.
コンピュータを再起動しない場合は,バックグラウンドで実行しているアプリはそのままバックグラウンドで実行されたままです.スイッチをオフにしても,バックグラウンドで実行中のアプリは終了しません.


図5
[バックグラウンドで実行] の機能を無効にする