Pascal 日和 ホームページ



更新:2026-04-18



備忘録インデックス

Object Pascal 備忘録  (Free Pascal OBJFPCモード)



アプリのマニフェストを設定する


〜 Object Pascal(Free Pascal)のEXEにManifestを設定する方法 〜




1. はじめに


Windowsには、アプリが自分の動作条件や必要とする機能を OS に伝えるためのアプリケーション マニフェスト(Application Manifest)という仕組みがあります。以降マニフェストと呼びます。

マニフェストは実行ファイルに付随する小さなXML情報で、アプリがどのような環境で動くべきかをWindowsに宣言する役割を持ちます。

バージョン情報設定アプリアイコン設定は、アプリ(EXE)やDLLのファイルのプロパティ情報の設定であり、アプリの挙動自体に作用するものではありませんが、マニフェストの設定はアプリの挙動について影響を与えるものもあります。


マニフェストの設定項目(抜粋)


  • アプリ(EXE)やDLLの識別情報

  • 外部ライブラリ(DLL/コンポーネント)の依存関係

  • UAC(ユーザーアカウント制御)の昇格レベル

  • アプリケーション互換性(対応OS)

  • 高DPI対応

  • 長いパス名対応(MAX_PATH(260)の制限解除)

  • プロセスの既定のコードページの設定


詳細にしては https://learn.microsoft.com/ja-jp/windows/win32/sbscs/application-manifests を参照してください。





2. マニフェストの設定 - Lazarusの場合


LazarusのIDEを使用するとマニフェストファイル(XML)を意識しないで設定することができます。

IDEによりマニフェストファイルが作成されてアプリに設定されます。

この方法の場合、マニフェストの設定項目はIDEの設定項目に限定されます。


2.1 LazarusのIDEでマニフェストを設定する


Lazarusのメニュー[プロジェクト(P)]-[プロジェクトオプション...]で以下のウインドウを開き左の[アプリケーション]を選択します。


[マニフェストリソースを使う(テーマを有効にする)]をチェックします。チェックすると以下の設定が有効(活性化)になります。

・[DPIを意識]

アプリがDPIを意識する内容を選択します。Windows 10/11では、「Vista-8: on, 8.1/10+: per monitor/V2(True/PM_2)」を選択します。

・[実行レベル]

アプリの実行権限を選択します。

  • asInvoker
    親プロセスと同じ権限で実行する一般的なアプリの設定です。

  • highestAvailable
    現在のユーザが管理者ユーザの場合は管理者権限に昇格(UACダイアログが表示される)して実行され、標準ユーザの場合は標準権限で実行される設定です。

  • requireAdministrator
    必ず管理者権限に昇格(UACダイアログが表示される)して実行される設定です。

・[UIアクセス(uiAccess)]

通常は設定しません。自動化ツールやアクセシビリティ支援ツールが、管理者権限の画面を操作する必要がある場合のみ使用されます。コードのデジタル署名が必要になります。

・[Long path awareness(Windows 10 1607+)]

チェックするとMAX_PATH(260文字)の制限が解除されます。

・[ANSI codepage is UTF-8(Windows 10 1903+)]

Window ANSI系APIが、UTF-8で動作するように設定します。

日本語版Windows(ja-JP)ではCP932(Shift_JISの拡張版)で動作します。

・[名前]

アプリの識別名を指定します。実行ファイル名と同じある必要はありません。できるだけユニークになるように設定します。
「会社や組織.部門や製品.アプリ名」など"."表記で設定するとニユーク性が高まります。
ユニークではなくても動作しますが、ユニークな設定をしましょう。

・[説明]

簡単な説明(コメント)です。任意で、空でも問題ありません。





3. マニフェストファイル(XML)


3.1 マニフェストファイルの設定


Lazaris IDEではIDEのGUIで設定できますが、Free Pascalなどのコンパイラを使用する場合はマニフェスト(XML)をファイルとして作成します。

アプリに対してマニフェストを有効化するためには以下の方法があります。


  1. マニフェストファイルをアプリ(EXE)と同じ場所に配置する
    アプリが、Appli01.exe であればマニフェストファイル名はそれに .manifest を付けてものとして同一ディレクトリに配置する
    ・Appli01.exe
    ・Appli01.exe.manifest

  2. マニフェストファイルをアプリのリソースとして組み込む
    設定方法は後述


3.2 マニフェストファイル(XML)の例


XMLの構文に従って書き方は決まっているので、ひな型を用意して、それを加工して利用するのがよいと思います。

Windowx 11アプリ用マニフェストの例を以下に示します。ひな型として利用してください。

Lazarus IDEで設定できる項目に加えて「ウインドウのフィルター処理を無効化」と「印刷時のドライバープロセス分離」を加えてみました。


コードページ UTF-8 で作成してください(MBCSは使用していないので実際にはUTF-8ではなくてもよいですが)。

 マニフェストの例 : app.manifest
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="CompanyName.ProductName.AppName"
    version="1.0.0.0"
    processorArchitecture="*"
  />
  <description>Windows Application.</description>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        processorArchitecture="*"
        publicKeyToken="6595b64144ccf1df"
        language="*"
      />
    </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
        <!-- requestedExecutionLevel level="highestAvailable" uiAccess="false"/ -->
        <!-- requestedExecutionLevel level="requireAdministrator" uiAccess="false"/ -->
      </requestedPrivileges>
    </security>
  </trustInfo>
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
    </application>
  </compatibility>
  <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>True/PM_V2</dpiAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">
      <disableWindowFiltering>True</disableWindowFiltering>
      <printerDriverIsolation>True</printerDriverIsolation>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
      <dpiAwareness>PerMonitorV2, PerMonitor</dpiAwareness>
      <longPathAware>True</longPathAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
      <activeCodePage>UTF-8</activeCodePage>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>


上記のマニフェストファイルに簡単なコメントを付けたものを以下に示します。

マイクロソフトの説明サイトと合わせて参照すると詳細はわかると思いますのでここでは個々の設定の詳細については述べません。


コードページ UTF-8 で作成してください。

 マニフェストの例(コメント付き)
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

  <!-- WindowsのアプリやDLLの識別情報 -->
  <!-- name属性はアプリを区別するユニークな名前が望ましい -->
  <assemblyIdentity
    type="win32"
    name="CompanyName.ProductName.AppName"
    version="1.0.0.0"
    processorArchitecture="*"
  />

  <!-- アプリの説明文(指定は任意でWindowsのUIには通常表示されない) -->
  <description>Windows Application.</description>

  <!-- 外部ライブラリ(DLL/コンポーネント)の依存関係 -->
  <!-- GUIアプリはCommon Controls v6を指定する(指定しないと古い外観になる) -->
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        processorArchitecture="*"
        publicKeyToken="6595b64144ccf1df"
        language="*"
      />
    </dependentAssembly>
  </dependency>

  <!-- UAC(ユーザーアカウント制御)の昇格レベル -->
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <!-- ▼Windowsの管理者権限の昇格レベルを定義する -->
        <!-- ・level="asInvoker"は呼び出し元と同じ権限を要求される(UACダイアログは表示されない) -->
        <!-- ・level="requireAdministrator"は管理者権限を要求される(管理者権限に昇格する場合はUACダイアログが表示される) -->
        <!-- ・level="highestAvailable"ユーザが持っている最も高い権限を要求される(管理者権限に昇格する場合はUACダイアログが表示される) -->
        <!-- ※親プロセスがすでに管理者権限で動作している場合はいずれの場合もUACダイアログは表示されない -->
        <!-- 以下のコメントの中から1つをコメントの外に指定する。何も指定しない場合は"asInvoker"指定と同じ -->
        <!--
        <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
        <requestedExecutionLevel level="highestAvailable" uiAccess="false"/>
        <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
        -->
      </requestedPrivileges>
    </security>
  </trustInfo>

  <!-- アプリケーション互換性 -->
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!-- アプリがサポートするWindowsバージョン(指定順に意味はない) -->
      <!-- アプリがターゲットとしないバージョンについては指定不要 -->
      <!-- ▼Windows 10、Windows 11、Windows Server 2016、Windows Server 2019、Windows Server 2022 -->
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
      <!-- ▼Windows 8.1、Windows Server 2012 R2 -->
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
      <!-- ▼Windows 8、Windows Server 2012 -->
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
      <!-- ▼Windows 7、Windows Server 2008 R2 -->
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <!-- ▼Windows Vista および Windows Server 2008 -->
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
    </application>
  </compatibility>

  <!-- Windows固有の動作設定 -->
  <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <!-- ▼高DPI対応(Windows Vista以降) -->
      <!-- ・Trueは高DPI対応、PM_V2はWindows 10を含む複数モニター対応 -->
      <dpiAware>True/PM_V2</dpiAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">
      <!-- ▼ウインドウのフィルター処理を無効化 -->
      <!-- Trueにするとウインドウのフィルター処理を無効にする -->
      <disableWindowFiltering>True</disableWindowFiltering>
      <!-- ▼印刷時のドライバープロセス分離 -->
      <!-- Trueにすると印刷ドライバーをプロセスから分離される -->
      <printerDriverIsolation>True</printerDriverIsolation>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
      <!-- ▼高DPI対応(Windows 10 バージョン 1607以降) -->
      <!-- ・PerMonitorV2はWindows 10以降で推奨されるDPIモード(高DPI/複数モニター対応) -->
      <!-- ・PerMonitorはWindows 8.1以降で推奨されるDPIモード(高DPI/複数モニター対応) -->
      <dpiAwareness>PerMonitorV2, PerMonitor</dpiAwareness>
      <!-- ▼MAX_PATH(260文字)の制限解除(Windows 10 バージョン 1607以降) -->
      <!-- ・TrueにするとMAX_PATH(260文字)の制限が解除される -->
      <longPathAware>True</longPathAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
      <!-- ▼プロセスコードページをUTF-8に設定する(Windows バージョン 1903以降) -->
      <!-- ・UTF-8はWindows API(ANSI系)がUTF-8でのやり取りにかわる -->
      <!-- ※ UTF-8を指定するとGetACP関数の戻り値もUTF-8(65001)になる -->
      <!-- ※ OS全体のUTF-8モードを変更せず、アプリ単体でUTF-8が使用される -->
      <!-- ※ Windows 11ではja-JPなどのローケール名を指定するともできるja-JPは932となる -->
      <activeCodePage>UTF-8</activeCodePage>
    </asmv3:windowsSettings>
  </asmv3:application>

</assembly>


app.manifest をひな型にする場合、各アプリに展開する場合は最低限以下のname属性にユニークな識別子を設定してください。アプリファイル名に合わせる必要はありません。ユニークではなくてもたいていは動作しますが、ルールなので。

  <assemblyIdentity
    type="win32"
    name="ユニークな識別子"
    version="1.0.0.0"
    processorArchitecture="*"
  />


ひとつのアプリで複数のマニフェストファイルを設定することはできません。重複しない項目に分けて複数のマニフェストファイルにすることもできません。

Lazarus IDEのGUIでマニフェストを設定した場合は、以降のリソースでマニフェストを設定する方法は使用できません。エラーとなります。リソースで設定したい場合はIDEの[□マニフェイトリソースを使う(テーマを有効にする)]のチェックをオフにしてください。


不要な設定や設定したくない項目については削除可能です。

コンソールアプリの場合「Common Controls v6を指定」や「高DPI対応」は、そもそも不要なので削除可能ですが、存在しても無視されるだけなのでそのままでも問題ありません。


マニフェストファイルに不備があると実行開始時に以下のようなエラーとなり終了します。

コンパイルではエラーにならないので、必ず実行確認は必要です。



このアプリケーションのサイド バイ サイド構成が正しくないため、アプリケーションを開始できませんでした。詳細については、アプリケーションのイベント ログを参照するか、コマンド ライン ツール sxstrace.exe を使用してください。


マニフェストファイル(XML)自体の説明は以上です。


以降、主な設定の確認デモです。





4. デモアプリによる機能確認


以降では、各機能ごとの設定方法やアプリの機能確認デモを紹介します。
追加した「ウインドウのフィルター処理を無効化」と「印刷時のドライバープロセス分離」については割愛します。
各アプリは機能確認のためだけの最低限のコードを示しています。アプリケーションとしてのひな型にはなりませんので注意してください。
自分でマニフェストの設定を有効にしたり無効にしたりして違いを見てください。
コースコードに以下のディレクティブがある場合はマニフェストが有効です。
{$R Manifest.rc}
これをコメントアウトするとマニフェストが無効になります。
 // {$R Manifest.rc}

リソースの設定についてはこちらも参照してください。バージョン情報を設定するアプリのアイコンを設定する
プログラムやマニフェストなど重複する内容が多いですが、いちいち他の場所を参照しないでよいように、すべて表示しています。

ファイル名が重複するので、デモごとにディレクトリ(フォルダ)を分けてください。
Object Pascal 備忘録ページから[DM0007A.zip]をダウンロードすると全ファイルがデモ別のディレクトリ(フォルダ)で構成されています。

Windows Updateの問題に対する対応について(解消済み)。

リソースコンパイルも含むので以下の情報も確認してください。
Windows Updateでcrtdll.dllが新しい形式に更新されるとリソースコンパイラwindres.exeが動作しなくなります。
 Windows Updateの問題に対する対応について
 ※この問題は2026年4月15日のWindows Updateで一旦ロールバックされたようで、解消しています。

上記問題が生じた場合に対応するコマンドスクリプトも作成したので参照してください。
 Free Pascal用のコマンドスクリプト(その2)   TDM-GCCも必要ですTDM-GCC インストール参照。

fpc64.cmd でエラーになる場合は fpcrc64.cmd を使用してください。


デモ インデックス




デモ 1. UAC管理者権限昇格のデモ(その1)


アプリがWindowsのシステムに影響を与える処理をするには、管理者権限が必要になります。

例えば、Windowsの「Program Files」にファイルを作成したい場合は、アプリを管理種権限に昇格させる必要があります。

マニフェストでは「UAC(ユーザーアカウント制御)の昇格レベル」で「<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>」を指定するとアプリの起動時に管理者権限に昇格しUACダイアログが表示されます。管理種権限のプロセスから起動された場合は管理者権限が継承されるのでUACダイアログは表示されません。


このデモは、Windowsの「Program Files」 に「TestFile.txt」を作成して削除します。

マニフェストファイルはアプリ(EXE)とは別ファイルとして配置します。


プログラムファイルは以下のセットです。同一ディレクトリに置いてください。
ファイルはコードページ UTF-8(65001)で作成してください。

  • ManifestDemo1.pas

  • ManifestDemo1.exe.manifest


 UAC昇格デモ(外部マニフェスト) : ManifestDemo1.pas
(*****************************************************************************)
(* プログラム - ManifestDemo1                                                *)
(*   UAC管理者権限昇格のデモ(外部マニフェストファイル使用)                   *)
(*****************************************************************************)
program ManifestDemo1;

{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}

uses
  Windows, SysUtils, WinDirs;

(*****************************************************************************)
(* プログラムブロック - 宣言部                                               *)
(*****************************************************************************)

{ 定数 }
const
  SECURITY_NT_AUTHORITY : TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
  FILENAME = 'TestFile.txt';

{ 変数 }
var
  ProgramFilesDir : String;
  FName           : String;
  File1           : TextFile;

{--------------------------------------------------------}
{ 関数 - WinAPI参照 (Windows Unitで宣言されていないため) }
{--------------------------------------------------------}
function CheckTokenMembership(TokenHandle: HANDLE; SidToCheck: PSID; out IsMember: WINBOOL): WINBOOL;
                             stdcall; external 'advapi32.dll' name 'CheckTokenMembership';

{-------------------------}
{ 関数 - アプリの権限確認 }
{-------------------------}
function IsInGroup(Group: DWORD): Boolean;
var
  PIdentifierAuthority : TSIDIdentifierAuthority;
  PtSid                : PSID;
  IsMember             : WINBOOL;
begin
  PIdentifierAuthority := SECURITY_NT_AUTHORITY;
  Result := False;
  PtSid  := Nil;
  try
    if AllocateAndInitializeSid(PIdentifierAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, Group, 0, 0, 0, 0, 0, 0, PtSid) then
    begin
      if CheckTokenMembership(0, PtSid, IsMember) then
      begin
        Result := IsMember;
      end;
    end;
  finally
    if PtSid <> Nil then
    begin
      FreeSid(PtSid);
    end;
  end;
end;

(*****************************************************************************)
(* プログラムブロック - 実行文部                                             *)
(*****************************************************************************)
begin
  SetMultiByteConversionCodePage(CP_UTF8);
  SetMultiByteRTLFileSystemCodePage(CP_UTF8);
  TextRec(File1).Mode := fmClosed;
  try
    try
      WriteLn;
      { アプリの実行レベルを表示 }
      WriteLn('[アプリの実行レベル]');
      if IsInGroup(DOMAIN_ALIAS_RID_ADMINS) then
      begin
        WriteLn('管理者権限で実行中');
        WriteLn;
      end;
      Writeln('管理者グループ       : ', IsInGroup(DOMAIN_ALIAS_RID_ADMINS).ToString(TUseBoolStrs.True));
      Writeln('一般ユーザグループ   : ', IsInGroup(DOMAIN_ALIAS_RID_USERS).ToString(TUseBoolStrs.True));
      Writeln('ゲストグループ       : ', IsInGroup(DOMAIN_ALIAS_RID_GUESTS).ToString(TUseBoolStrs.True));
      Writeln('パワーユーザグループ : ', IsInGroup(DOMAIN_ALIAS_RID_POWER_USERS).ToString(TUseBoolStrs.True));
      WriteLn;
      { C:\Program Files に'TestFile.dat'を作成する(要管理者権限) }
      ProgramFilesDir := GetWindowsSpecialDir(CSIDL_PROGRAM_FILES, False);
      FName := ConcatPaths([ProgramFilesDir, FILENAME]);
      AssignFile(File1, FName);
      Rewrite(File1); { 標準ユーザ権限の場合例外(EInOutError)が発生する }
      WriteLn('"', FName, '" の作成に成功しました')
    except
      on Ex: EInOutError do
      begin
        WriteLn(StdErr, '*** I/Oエラー(', Ex.ErrorCode, ') : ', Ex.Message);
      end;
      on Ex: Exception do
      begin
        WriteLn(StdErr, '*** エラー : ', Ex.Message);
      end;
    end;
  finally
    if TextRec(File1).Mode <> fmClosed then
    begin
      CloseFile(File1);   { 'TestFile.dat'をクローズ }
    end;
    if FileExists(FName) then
    begin
      DeleteFile(FName);  { 作成した'TestFile.dat'を削除 }
      WriteLn;
      WriteLn('"', FName, '" を削除しました(後始末)')
    end
    else
    begin
      WriteLn;
      WriteLn('"', FName, '" の作成に失敗しました')
    end;
    WriteLn(StdErr);
    Write(StdErr, 'Enterキーを押してください...');
    ReadLn;
  end;
end.


 マニフェスト : ManifestDemo1.exe.manifest
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="e-hiyori.org.ManifestDemo1"
    version="1.0.0.0"
    processorArchitecture="*"
  />
  <description>Windows Application.</description>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        processorArchitecture="*"
        publicKeyToken="6595b64144ccf1df"
        language="*"
      />
    </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
    </application>
  </compatibility>
  <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>True/PM_V2</dpiAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">
      <disableWindowFiltering>True</disableWindowFiltering>
      <printerDriverIsolation>True</printerDriverIsolation>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
      <dpiAwareness>PerMonitorV2, PerMonitor</dpiAwareness>
      <longPathAware>True</longPathAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
      <activeCodePage>UTF-8</activeCodePage>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>


ManifestDemo1.pas をコンパイルして ManifestDemo1.exe を作成します。

C:\PG\FreePascal\ManifestDemo_001>fpcrc64.cmd ManifestDemo1.pas
Free Pascal Compiler version 3.2.2 [2021/05/15] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling ManifestDemo1.pas
Linking ManifestDemo1.exe
121 lines compiled, 0.1 sec, 87056 bytes code, 6660 bytes data


ManifestDemo1.exe を実行するとUACダイアログが表示され、管理権限のターミナルが開いて実行結果が表示されます。




[アプリの実行レベル]
管理者権限で実行中

管理者グループ       : True
一般ユーザグループ   : True
ゲストグループ       : False
パワーユーザグループ : False

"C:\Program Files\TestFile.txt" の作成に成功しました

"C:\Program Files\TestFile.txt" を削除しました(後始末)

Enterキーを押してください...





デモ 2. UAC管理者権限昇格のデモ(その2)


このデモは、Windowsの「Program Files」 に「TestFile.txt」を作成して削除します。

マニフェストファイルをリソースファイルとしてアプリ(EXE)に組み込みます。


プログラムファイルは以下のセットです。同一ディレクトリに置いてください。
ファイルはコードページ UTF-8(65001)で作成してください。

  • ManifestDemo2.pas

  • UAC.manifest

  • UAC.rc


 UAC昇格デモ : ManifestDemo2.pas
(*****************************************************************************)
(* プログラム - ManifestDemo2                                                *)
(*   UAC管理者権限昇格のデモ(マニフェストファイルをリソースとして組み込み)   *)
(*****************************************************************************)
program ManifestDemo2;

{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}

uses
  Windows, SysUtils, WinDirs;

{$R UAC.rc}

(*****************************************************************************)
(* プログラムブロック - 宣言部                                               *)
(*****************************************************************************)

{ 定数 }
const
  SECURITY_NT_AUTHORITY : TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
  FILENAME = 'TestFile.txt';

{ 変数 }
var
  ProgramFilesDir : String;
  FName           : String;
  File1           : TextFile;

{--------------------------------------------------------}
{ 関数 - WinAPI参照 (Windows Unitで宣言されていないため) }
{--------------------------------------------------------}
function CheckTokenMembership(TokenHandle: HANDLE; SidToCheck: PSID; out IsMember: WINBOOL): WINBOOL;
                             stdcall; external 'advapi32.dll' name 'CheckTokenMembership';

{-------------------------}
{ 関数 - アプリの権限確認 }
{-------------------------}
function IsInGroup(Group: DWORD): Boolean;
var
  PIdentifierAuthority : TSIDIdentifierAuthority;
  PtSid                : PSID;
  IsMember             : WINBOOL;
begin
  PIdentifierAuthority := SECURITY_NT_AUTHORITY;
  Result := False;
  PtSid  := Nil;
  try
    if AllocateAndInitializeSid(PIdentifierAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, Group, 0, 0, 0, 0, 0, 0, PtSid) then
    begin
      if CheckTokenMembership(0, PtSid, IsMember) then
      begin
        Result := IsMember;
      end;
    end;
  finally
    if PtSid <> Nil then
    begin
      FreeSid(PtSid);
    end;
  end;
end;

(*****************************************************************************)
(* プログラムブロック - 実行文部                                             *)
(*****************************************************************************)
begin
  SetMultiByteConversionCodePage(CP_UTF8);
  SetMultiByteRTLFileSystemCodePage(CP_UTF8);
  TextRec(File1).Mode := fmClosed;
  try
    try
      WriteLn;
      { アプリの実行レベルを表示 }
      WriteLn('[アプリの実行レベル]');
      if IsInGroup(DOMAIN_ALIAS_RID_ADMINS) then
      begin
        WriteLn('管理者権限で実行中');
        WriteLn;
      end;
      Writeln('管理者グループ       : ', IsInGroup(DOMAIN_ALIAS_RID_ADMINS).ToString(TUseBoolStrs.True));
      Writeln('一般ユーザグループ   : ', IsInGroup(DOMAIN_ALIAS_RID_USERS).ToString(TUseBoolStrs.True));
      Writeln('ゲストグループ       : ', IsInGroup(DOMAIN_ALIAS_RID_GUESTS).ToString(TUseBoolStrs.True));
      Writeln('パワーユーザグループ : ', IsInGroup(DOMAIN_ALIAS_RID_POWER_USERS).ToString(TUseBoolStrs.True));
      WriteLn;
      { C:\Program Files に'TestFile.dat'を作成する(要管理者権限) }
      ProgramFilesDir := GetWindowsSpecialDir(CSIDL_PROGRAM_FILES, False);
      FName := ConcatPaths([ProgramFilesDir, FILENAME]);
      AssignFile(File1, FName);
      Rewrite(File1); { 標準ユーザ権限の場合例外(EInOutError)が発生する }
      WriteLn('"', FName, '" の作成に成功しました')
    except
      on Ex: EInOutError do
      begin
        WriteLn(StdErr, '*** I/Oエラー(', Ex.ErrorCode, ') : ', Ex.Message);
      end;
      on Ex: Exception do
      begin
        WriteLn(StdErr, '*** エラー : ', Ex.Message);
      end;
    end;
  finally
    if TextRec(File1).Mode <> fmClosed then
    begin
      CloseFile(File1);   { 'TestFile.dat'をクローズ }
    end;
    if FileExists(FName) then
    begin
      DeleteFile(FName);  { 作成した'TestFile.dat'を削除 }
      WriteLn;
      WriteLn('"', FName, '" を削除しました(後始末)')
    end
    else
    begin
      WriteLn;
      WriteLn('"', FName, '" の作成に失敗しました')
    end;
    WriteLn(StdErr);
    Write(StdErr, 'Enterキーを押してください...');
    ReadLn;
  end;
end.


 マニフェスト : UAC.manifest
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="e-hiyori.org.ManifestDemo2"
    version="1.0.0.0"
    processorArchitecture="*"
  />
  <description>Windows Application.</description>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        processorArchitecture="*"
        publicKeyToken="6595b64144ccf1df"
        language="*"
      />
    </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
    </application>
  </compatibility>
  <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>True/PM_V2</dpiAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">
      <disableWindowFiltering>True</disableWindowFiltering>
      <printerDriverIsolation>True</printerDriverIsolation>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
      <dpiAwareness>PerMonitorV2, PerMonitor</dpiAwareness>
      <longPathAware>True</longPathAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
      <activeCodePage>UTF-8</activeCodePage>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>


 リソースファイル : UAC.rc
/////////////////////////////////////////////////////////////////////////////
//
// 本ファイルのコードページ
//

#pragma code_page(65001)    // Free Pascalの{$CODEPAGE UTF8}と同じようなもの。

/////////////////////////////////////////////////////////////////////////////
//
// アプリケーションのマニフェストを設定する。
//

#define CREATEPROCESS_MANIFEST_RESOURCE_ID  1
#define RT_MANIFEST                         24

CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "UAC.manifest"


ManifestDemo2.pas コンパイルして ManifestDemo2.exe を作成します。


C:\PG\FreePascal\ManifestDemo_002>fpcrc64.cmd ManifestDemo2.pas
Free Pascal Compiler version 3.2.2 [2021/05/15] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling ManifestDemo2.pas
Compiling resource C:\PG\FreePascal\ManifestDemo_002\UAC.rc
Compiling resource ManifestDemo2.obj
Linking ManifestDemo2.exe
123 lines compiled, 0.9 sec, 87056 bytes code, 6660 bytes data


ManifestDemo2.exe を実行するとUACダイアログが表示され、管理権限のターミナルが開いて実行結果が表示されます。




[アプリの実行レベル]
管理者権限で実行中

管理者グループ       : True
一般ユーザグループ   : True
ゲストグループ       : False
パワーユーザグループ : False

"C:\Program Files\TestFile.txt" の作成に成功しました

"C:\Program Files\TestFile.txt" を削除しました(後始末)

Enterキーを押してください...





デモ 3. マニフェストファイルの設定情報を表示するデモ


このデモは、アプリの実行権限(Windows APIで取得)やその他の設定内容(リソースのマニフェストXMLを参照)を表示します。

バージョン情報やアイコンのリソース定義との共存も問題ないことを示します。


プログラムファイルは以下のセットです。同一ディレクトリに置いてください。
ファイルはコードページ UTF-8(65001)で作成してください(AppIcon.icoは除く)。

  • ManifestDemo3.pas

  • app.manifest

  • Manifest.rc

  • VerInfo.rc

  • Icon.rc

  • AppIcon.ico


 マニフェスト設定情報表示デモ : ManifestDemo3.pas
(*****************************************************************************)
(* プログラム - ManifestDemo3                                                *)
(*   マニフェストファイル(組み込み)の設定情報を表示                          *)
(*****************************************************************************)
program ManifestDemo3;

{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
{$WARN 4104 OFF}  (* UnicodeString <- AansiString   *)
{$WARN 4105 OFF}  (* AnsiString    <- UnicodeString *)

uses
  Windows, Classes, SysUtils, DOM, XMLRead;

{$R Manifest.rc}
{$R VerInfo.rc}
{$R Icon.rc}
// {$R MyResource.rc}  { Manifest & Icon & VersionInfo 合体版 }

(*****************************************************************************)
(* プログラムブロック - 宣言部                                               *)
(*****************************************************************************)

{ 定数 }
const
  SECURITY_NT_AUTHORITY : TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));

{ 型 }
type
  { マニフェスト情報 }
  TManifestInfo = record
    DpiAware               : String;
    DpiAwareness           : String;
    LongPathAware          : String;
    ActiveCodePage         : String;
    DisableWindowFiltering : String;
    PrinterDriverIsolation : String;
  end;

{ 変数 }
var
  ManifestXML : String;
  Info        : TManifestInfo;
  Dict        : TStringList;
  OSList      : TStringList;
  I           : Integer;

{--------------------------------------------------------}
{ 関数 - WinAPI参照 (Windows Unitで宣言されていないため) }
{--------------------------------------------------------}
function CheckTokenMembership(TokenHandle: HANDLE; SidToCheck: PSID; out IsMember: WINBOOL): WINBOOL;
                             stdcall; external 'advapi32.dll' name 'CheckTokenMembership';

{--------------------------}
{ 関数 - Manigest XML 取得 }
{--------------------------}
function GetManifestXml(const ExePath: String): String;
var
  HLib    : HMODULE;
  HRes    : HANDLE;
  HGlob   : HGLOBAL;
  PData   : Pointer;
  ResSize : DWORD;
begin
  Result := '';
  { EXEファイル(自分)をリソースとしてロード }
  HLib := LoadLibraryEx(PChar(ExePath), 0, LOAD_LIBRARY_AS_DATAFILE);
  if HLib = 0 then
  begin
    Exit;
  end;
  try
    { RT_MANIFEST(ID: 1)を探す }
    HRes := FindResource(HLib, MAKEINTRESOURCE(1), RT_MANIFEST);
    if HRes <> 0 then
    begin
      ResSize := SizeofResource(HLib, HRes);
      HGlob := LoadResource(HLib, HRes);
      if HGlob <> 0 then
      begin
        PData := LockResource(hGlob);
        if PData <> Pointer(Nil) then
        begin
          { XMLテキストとして取得 }
          SetString(Result, PChar(PData), ResSize);
        end;
      end;
    end;
  finally
    FreeLibrary(HLib);
  end;
end;

{-------------------------}
{ 関数 - アプリの権限確認 }
{-------------------------}
function  IsInGroup(Group: DWORD): Boolean;
var
  PIdentifierAuthority : TSIDIdentifierAuthority;
  PtSid                : PSID;
  IsMember             : WINBOOL;
begin
  PIdentifierAuthority := SECURITY_NT_AUTHORITY;
  Result := False;
  PtSid  := Nil;
  try
    if AllocateAndInitializeSid(PIdentifierAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, Group, 0, 0, 0, 0, 0, 0, PtSid) then
    begin
      if CheckTokenMembership(0, PtSid, IsMember) then
      begin
        Result := IsMember;
      end;
    end;
  finally
    if PtSid <> Nil then
    begin
      FreeSid(PtSid);
    end;
  end;
end;

{---------------------------------}
{ 関数 - Manifestのノード値を取得 }
{---------------------------------}
function GetManifestValue(const XMLStr: String; const TargetName: String): String;
var
  Doc     : TXMLDocument;
  SStream : TStringStream;
  { 内部関数 - 再帰検索を行う }
  function FindRecursive(Node: TDOMNode): String;
  var
    Child: TDOMNode;
  begin
    Result := '';
    if Node = Nil then
    begin
      Exit;
    end;
    { 要素ノードかつ名前が一致するか(接頭辞なしのLocalNameで比較) }
    if (Node.NodeType = ELEMENT_NODE)
       and (SameText(Node.LocalName, TargetName) or SameText(Node.NodeName, TargetName)) then
    begin
      if Node.FirstChild <> Nil then
      begin
        Result := Node.FirstChild.NodeValue;
        Exit;
      end;
    end;
    { 子ノードを再起検索 }
    Child := Node.FirstChild;
    while Child <> Nil do
    begin
      Result := FindRecursive(Child);
      if Result <> '' then
      begin
        Exit;
      end;
      Child := Child.NextSibling;
    end;
  end;
begin
  Result  := '';
  Doc     := Nil;
  SStream := Nil;
  try
    try
      { XMLを読み込む }
      SStream := TStringStream.Create(XMLStr, TEncoding.UTF8);
      ReadXMLFile(Doc, SStream);
      Result := FindRecursive(Doc);
    except
      on Ex: Exception do
      begin
        Result := '<データなし>'
      end;
    end;
  finally
    if Result = '' then
    begin
      Result := '<データなし>';
    end;
    SStream.Free;
    Doc.Free;
  end;
end;

{-----------------------------------}
{ 関数 - Manifestの属性値一覧を取得 }
{-----------------------------------}
function GetManifestAttributeList(const XMLStr: String; const TagName, AttrName: String): TStringList;
var
  Doc     : TXMLDocument;
  SStream : TStringStream;
  Nodes   : TDOMNodeList;
  I       : Integer;
  Attr    : TDOMNode;
begin
  Result  := TStringList.Create;
  Doc     := Nil;
  SStream := TStringStream.Create(XMLStr, TEncoding.UTF8);
  try
    try
      ReadXMLFile(Doc, SStream);
      { 指定したタグ名をすべて取得 }
      Nodes := Doc.GetElementsByTagName(TagName);
      if Assigned(Nodes) then
      begin
        for I := 0 to Nodes.Count - 1 do
        begin
          { 属性を探す }
          Attr := Nodes.Item[I].Attributes.GetNamedItem(AttrName);
          if Assigned(Attr) then
            Result.Add(Attr.NodeValue);
        end;
      end;
    except
      on Ex: Exception do
      begin
        Result.Add('<データなし>');
      end;
    end;
  finally
    SStream.Free;
    Doc.Free;
  end;
end;

{-----------------------------}
{ 関数 - マニフェスト情報取得 }
{-----------------------------}
function GetManifestInfo(const XMLStr: String): TManifestInfo;
begin
  Result.DpiAware               := GetManifestValue(XMLStr, 'dpiAware');
  Result.DpiAwareness           := GetManifestValue(XMLStr, 'dpiAwareness');
  Result.LongPathAware          := GetManifestValue(XMLStr, 'longPathAware');
  Result.ActiveCodePage         := GetManifestValue(XMLStr, 'activeCodePage');
  Result.DisableWindowFiltering := GetManifestValue(XMLStr, 'disableWindowFiltering');
  Result.PrinterDriverIsolation := GetManifestValue(XMLStr, 'printerDriverIsolation');
end;

{-----------------------}
{ 関数 - OS名の辞書作成 }
{-----------------------}
function CreateOSDictionary: TStringList;
begin
  Result := TStringList.Create;
  Result.CaseSensitive := False;
  Result.Values['{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}'] := 'Windows 10/11';
  Result.Values['{1f676c76-80e1-4239-95bb-83d0f6d0da78}'] := 'Windows 8.1';
  Result.Values['{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}'] := 'Windows 8';
  Result.Values['{35138b9a-5d96-4fbd-8e2d-a2440225f93a}'] := 'Windows 7';
  Result.Values['{e2011457-1546-43c5-a5fe-008deee3d3f0}'] := 'Windows Vista';
end;

{---------------------------------}
{ 関数 - GUIDに対応するOS名を返す }
{---------------------------------}
function GUIDToOSName(const GUID: String; Dict: TStringList): String;
begin
  Result := Dict.Values[GUID];
  if Result = '' then
  begin
    Result := 'Unknown OS (' + GUID + ')';
  end;
end;

(*****************************************************************************)
(* プログラムブロック - 実行文部                                             *)
(*****************************************************************************)
begin
  { Manifestで「UTF-8」の設定があれば次の2行は不要(CP_UTF8が設定される)。あっても良い }
  SetMultiByteConversionCodePage(CP_UTF8);
  SetMultiByteRTLFileSystemCodePage(CP_UTF8);
  OSList := Nil;
  Dict   := Nil;
  try
    try
      WriteLn;
      WriteLn('[アプリの実行レベル]');
      Writeln('管理者グループ       : ', IsInGroup(DOMAIN_ALIAS_RID_ADMINS).ToString(TUseBoolStrs.True));
      Writeln('一般ユーザグループ   : ', IsInGroup(DOMAIN_ALIAS_RID_USERS).ToString(TUseBoolStrs.True));
      Writeln('ゲストグループ       : ', IsInGroup(DOMAIN_ALIAS_RID_GUESTS).ToString(TUseBoolStrs.True));
      Writeln('パワーユーザグループ : ', IsInGroup(DOMAIN_ALIAS_RID_POWER_USERS).ToString(TUseBoolStrs.True));
      WriteLn;
      ManifestXML := GetManifestXml(ParamStr(0));
      WriteLn('[互換性(サポートOS)]');
      Dict   := CreateOSDictionary;
      OSList := GetManifestAttributeList(ManifestXML, 'supportedOS', 'Id');
      for I := 0 to OSList.Count - 1 do
      begin
        Writeln(GUIDToOSName(OSList[I], Dict));
      end;
      WriteLn;
      WriteLn('[マニフェスト情報]');
      Info := GetManifestInfo(ManifestXML);
      Writeln('dpiAware               : ', Info.DpiAware);
      Writeln('dpiAwareness           : ', Info.DpiAwareness);
      Writeln('longPathAware          : ', Info.LongPathAware);
      Writeln('activeCodePage         : ', Info.ActiveCodePage);
      WriteLn('disableWindowFiltering : ', Info.DisableWindowFiltering);
      WriteLn('printerDriverIsolation : ', Info.PrinterDriverIsolation);
      WriteLn;
      WriteLn('[WindowsのANSIコードページ]');
      WriteLn('Windows.GetACP : ', GetACP);
      WriteLn;
      WriteLn('[FreePascalのDefaultコードページ]');
      WriteLn('DefaultSystemCodePage         : ', DefaultSystemCodePage);
      WriteLn('DefaultFileSystemCodePage     : ', DefaultFileSystemCodePage);
      WriteLn('DefaultRTLFileSystemCodePage  : ', DefaultRTLFileSystemCodePage);
    except
      on Ex: Exception do
      begin
        WriteLn(StdErr, '*** エラー : ', Ex.Message);
      end;
    end;
  finally
    Dict.Free;
    OSList.Free;
    WriteLn;
  end;
end.


 マニフェスト : app.manifest
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="e-hiyori.org.ManifestDemo3"
    version="1.0.0.0"
    processorArchitecture="*"
  />
  <description>Windows Application.</description>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        processorArchitecture="*"
        publicKeyToken="6595b64144ccf1df"
        language="*"
      />
    </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
    </application>
  </compatibility>
  <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>True/PM_V2</dpiAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">
      <disableWindowFiltering>True</disableWindowFiltering>
      <printerDriverIsolation>True</printerDriverIsolation>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
      <dpiAwareness>PerMonitorV2, PerMonitor</dpiAwareness>
      <longPathAware>True</longPathAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
      <activeCodePage>UTF-8</activeCodePage>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>


 リソースファイル : Manifest.rc
/////////////////////////////////////////////////////////////////////////////
//
// 本ファイルのコードページ
//

#pragma code_page(65001)    // Free Pascalの{$CODEPAGE UTF8}と同じようなもの。

/////////////////////////////////////////////////////////////////////////////
//
// アプリケーションのマニフェストを設定する。
//

#define CREATEPROCESS_MANIFEST_RESOURCE_ID  1
#define RT_MANIFEST                         24

// GUIモード  (CUIモードでも利用可)
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app.manifest"

// CUIモード  (GUIモードのみに必要な情報を削除)
// CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "console.manifest"


 リソースファイル : VerInfo.rc
/////////////////////////////////////////////////////////////////////////////
//
// ヘッダファイル windres.h のインクルード
//

#include "windres.h"

/////////////////////////////////////////////////////////////////////////////
//
// 本ファイルのコードページ
//

#pragma code_page(65001)    // Free Pascalの{$CODEPAGE UTF8}と同じようなもの。

/////////////////////////////////////////////////////////////////////////////
//
// リソースの言語(日本語リソース)
//

LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT

/////////////////////////////////////////////////////////////////////////////
//
// バージョン情報データ (この値を編集する) ※変数は任意の名前で作成したもの。
//
// この情報データはフィクションであり、実在の人物・団体とは一切関係ありません。
//

#define VER_FILEVERSION           1,0,0,1   // ファイルバージョン
#define VER_FILEVERSION_STR       "1.0.0.1" // ファイルバージョン(文字列)

#define VER_PRODUCTVERSION        1,0,0,0   // 製品バージョン
#define VER_PRODUCTVERSION_STR    "1.0.0"   // 製品バージョン(文字列)

#define VS_FFI_FILEFLAGSMASK      0x3FL     // ファイルフラグマスク
#define VER_FFLAGS                0L        // ファイルフラグ

#define VER_FILETYPE              VFT_APP   // アプリ(EXE)。DLLの場合VFT_DLL

#define VER_COMPANYNAME_STR       "超力ソフト"               // 会社名
#define VER_FILEDESCRIPTION_STR   "ObjectPascalプログラム"   // ファイルの説明
#define VER_INTERNALNAME_STR      "ManifestDemo3"            // 内部名
#define VER_LEGALCOPYRIGHT_STR    "©2026 CHOURIKI-SOFT Inc." // 著作権表示
#define VER_LEGALTRADEMARKS_STR   ""                         // 商標/登録商標
#define VER_ORIGINALFILENAME_STR  "ManifestDemo3.exe"        // オリジナル名
#define VER_PRODUCTNAME_STR       "超力アプリ"               // 製品名
#define VER_COMMENTS_STR          "マニフェストデモ"         // 追加情報

/////////////////////////////////////////////////////////////////////////////
//
// バージョン情報定義
//

VS_VERSION_INFO VERSIONINFO
    FILEVERSION    VER_FILEVERSION
    PRODUCTVERSION VER_PRODUCTVERSION
    FILEFLAGSMASK  VS_FFI_FILEFLAGSMASK
    FILEFLAGS      VER_FFLAGS
    FILEOS         VOS_NT_WINDOWS32
    FILETYPE       VER_FILETYPE
    FILESUBTYPE    VFT2_UNKNOWN
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "041104B0"  // 0x0411(日本語), 0x04B0(=1200 ユニコード)
        BEGIN
            VALUE "CompanyName",      VER_COMPANYNAME_STR
            VALUE "FileDescription",  VER_FILEDESCRIPTION_STR
            VALUE "FileVersion",      VER_FILEVERSION_STR
            VALUE "InternalName",     VER_INTERNALNAME_STR
            VALUE "LegalCopyright",   VER_LEGALCOPYRIGHT_STR
            VALUE "LegalTrademarks",  VER_LEGALTRADEMARKS_STR
            VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR
            VALUE "ProductName",      VER_PRODUCTNAME_STR
            VALUE "ProductVersion",   VER_PRODUCTVERSION_STR
            VALUE "Comments",         VER_COMMENTS_STR
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x411, 1200  // 日本語, ユニコード
    END
END


 リソースファイル : Icon.rc
/////////////////////////////////////////////////////////////////////////////
//
// 本ファイルのコードページ
//

#pragma code_page(65001)    // Free Pascalの{$CODEPAGE UTF8}と同じようなもの。

/////////////////////////////////////////////////////////////////////////////
//
// アイコン
//

APPICON   ICON  "AppIcon.ico"


任意のアイコンを用意します。ManifestDemo3.pas と同じディレクトリに置きます。


  

ファイル名は「AppIcon.ico」とします。


ManifestDemo3.pas コンパイルして ManifestDemo3.exe を作成します。


C:\PG\FreePascal\ManifestDemo_003>fpcrc64.cmd ManifestDemo3.pas
Free Pascal Compiler version 3.2.2 [2021/05/15] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling ManifestDemo3.pas
Compiling resource C:\PG\FreePascal\ManifestDemo_003\Icon.rc
Compiling resource C:\PG\FreePascal\ManifestDemo_003\VerInfo.rc
Compiling resource C:\PG\FreePascal\ManifestDemo_003\Manifest.rc
Compiling resource ManifestDemo3.obj
Linking ManifestDemo3.exe
322 lines compiled, 0.6 sec, 255824 bytes code, 11092 bytes data


ManifestDemo3.exe を実行するとマニフェストの設定情報が表示されます。



[アプリの実行レベル]
管理者グループ       : False
一般ユーザグループ   : True
ゲストグループ       : False
パワーユーザグループ : False

[互換性(サポートOS)]
Windows 10/11
Windows 8.1
Windows 8
Windows 7
Windows Vista

[マニフェスト情報]
dpiAware               : True/PM_V2
dpiAwareness           : PerMonitorV2, PerMonitor
longPathAware          : True
activeCodePage         : UTF-8
disableWindowFiltering : True
printerDriverIsolation : True

[WindowsのANSIコードページ]
Windows.GetACP : 65001

[FreePascalのDefaultコードページ]
DefaultSystemCodePage         : 65001
DefaultFileSystemCodePage     : 65001
DefaultRTLFileSystemCodePage  : 65001





デモ 4. 長いパス名の検証デモ


マニフェストで「<longPathAware>True</longPathAware>」を設定すると、Windows APIで扱うパス名の長さ制限(MAX_PATH(260))が解除をされ長いパス名が使用できるようになります。

これはWindows APIを直接使用する場合の機能であり、Free Pascalの標準関数やライブラリはその限りではありません。Free Pascal 3.2.2 の AssignFile 手続きではでは MAX_PATH(260) ではなく、TextRecNameLength(256) の制限があり、Manifest の設定の影響は受けません。

現在、次リリースに向けて開発中の Free Pascal 3.3.1 では、長いパス名に対応する仕組みが実装されているようです。


プログラムファイルは以下のセットです。同一ディレクトリに置いてください。
ファイルはコードページ UTF-8(65001)で作成してください。

  • ManifestDemo4.pas

  • app.manifest

  • Manifest.rc


 長いパス名の検証デモ : ManifestDemo4.pas
(*****************************************************************************)
(* プログラム - ManifestDemo4                                                *)
(*   マニフェストによるロングパス有効化の検証                                *)
(*    - Windows APIでMAX_PATH(260)より長いパス名が有効                       *)
(*    - Free Pascal標準関数(AssignFileなど)では効果がない                    *)
(*****************************************************************************)
program ManifestDemo4;

{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}

uses
  Windows, SysUtils;

{$R Manifest.rc} (* この設定を外すとパス名の長さがMAX_PATH(260)に制限される *)

{ 定数 }
const
  TESTDIR = 'C:\PG\Test'; { テスト用の既存のディレクトリ(フォルダ)を指定する }

{ 変数 }
var
  FilePath : String;
  File1    : TextFile;
  FH       : HANDLE;
  FN       : UnicodeString;

{--------------------------------------------------------------}
{ 関数 - 長いバス(>MAX_PATH)のファイルを作成しフルパス名を返す }
{--------------------------------------------------------------}
function CreateLongPathFile: String;
const
  FILENAME  = 'TestFile.txt';
  NEWDIRLEN = 80;
  NEWDIRSET = ['A', 'B', 'C', 'D'];
var
  InitialDir : String;
  NewDir     : String;
  Ch         : Char;
begin
  InitialDir          := EmptyStr;
  TextRec(File1).Mode := fmClosed;
  try
    InitialDir := GetCurrentDir;
    if not SetCurrentDir(TESTDIR) then
    begin
      WriteLn('SetCurrentDir(TESTDIR)');
      RaiseLastOSError;
    end;
    WriteLn('(1) 起点のディレクトリ下にサブディレクトリ(A〜D)を作成しそのサブディレクトリをカレントディレクトリとする');
    for Ch in NEWDIRSET do
    begin
      NewDir := StringOfChar(Ch, NEWDIRLEN);
      if not DirectoryExists(NewDir) and not CreateDir(NewDir) then
      begin
        WriteLn('CreateDir(NewDir)');
        RaiseLastOSError;
      end
      else
      begin
        WriteLn(Ch, ' : ', {Ch, '..', Ch}NewDir);
      end;
      if not SetCurrentDir(NewDir) then
      begin
        WriteLn('SetCurrentDir(NewDir)');
        RaiseLastOSError;
      end;
    end;
    WriteLn;
    { 相対パス(<TextRecNameLength(256))でファイルを作成(FreePascal標準手続き使用) }
    WriteLn('(2) 標準手続き(AssignFile)でテスト用ファイルの相対パス名(<256)を設定');
    AssignFile(File1, FILENAME);
    WriteLn('<<< File1内のファイルパス名(name) >>>');
    WriteLn(String(TextRec(File1).name));
    WriteLn;
    WriteLn('(3) 標準手続き(Rewrite)でテスト用ファイル', FILENAME,'をサブディレクトリ下に作成');
    Rewrite(File1);
    WriteLn(File1, 'テストデータ');
    WriteLn('ファイルの作成が成功しました');
  finally
    if TextRec(File1).Mode <> fmClosed then
    begin
      CloseFile(File1);
    end;
    Result := ConcatPaths([GetCurrentDir, FILENAME]); { 戻り値にファイルのフルパス名を設定 }
    if InitialDir <> EmptyStr then
    begin
      if not SetCurrentDir(InitialDir) then
      begin
        WriteLn('SetCurrentDir(InitialDir)');
        RaiseLastOSError;
      end;
    end;
  end;
end;

(*****************************************************************************)
(* プログラムブロック - 実行文部                                             *)
(*****************************************************************************)
begin
  { Manifestで「<activeCodePage>UTF-8</activeCodePage>」の設定があれば次の2行は不要(CP_UTF8が設定される)。あっても良い }
  SetMultiByteConversionCodePage(CP_UTF8);
  SetMultiByteRTLFileSystemCodePage(CP_UTF8);
  FH := INVALID_HANDLE_VALUE;
  TextRec(File1).Mode := fmClosed;
  try
    try
      WriteLn;
      WriteLn('MAX_PATH           : ', MAX_PATH);
      WriteLn('TextRecNameLength  : ', TextRecNameLength);
      WriteLn;
      WriteLn('起点のディレクトリ : ', TESTDIR);
      WriteLn;
      { 長いバス(>MAX_PATH)のファイルを作成 }
      FilePath := CreateLongPathFile;
      WriteLn;
      WriteLn('(4) ファイルのフルパス名(起点のディレクトリ名+サブディレクトリ名(A〜D)+ファイル名)を表示');
      WriteLn(FilePath);
      WriteLn;
      { フルパス(>MAX_PATH)でファイルオープン(Windows API使用) }
      WriteLn('(5) Windows API(CreateFileW)でファイルのフルパス名を指定してオープン');
      FN := UTF8Decode(FilePath); { FN := FilePath; でもよい }
      FH := CreateFileW(PWideChar(FN), GENERIC_READ, FILE_SHARE_READ, Nil, OPEN_EXISTING, 0, 0);
      if FH = INVALID_HANDLE_VALUE then
      begin
        WriteLn('CreateFileW');
        RaiseLastOSError;
      end;
      WriteLn('フルパスでファイルのオープンが成功しました(ロングパス設定が有効)');
      WriteLn;
      { フルパス(>MAX_PATH)でファイルオープン(FreePascal標準手続き) }
      WriteLn('(6) 標準手続き(AssignFile)でファイルのフルパス(>=256)を設定 - 全部は入らない');
      AssignFile(File1, FilePath);
      WriteLn('<<< File1内のファイルパス名(name) >>>');
      WriteLn(String(TextRec(File1).name));
      WriteLn;
      {$IF DEFINED(VER3_2)}
      WriteLn('(7) 標準手続き(Reset)でファイルをオープン - Free Pascal 3.2.2 では上記の理由(パス不完全)でエラーになる(想定済)');
      Reset(File1);     { <== Free Pascal 3.2.2 ではここで例外が発生するはず }
      {$ENDIF}
      {$IF DEFINED(VER3_3) OR DEFINED(VER3_4)}
      WriteLn('(7) 標準手続き(Reset)でファイルをオープン - Free Pascal 3.3.1 では長いパス名に対応している');
      WriteLn('<<< File1内のファイルパス名(FullName) >>>');
      Reset(File1);     { <== Free Pascal 3.1.1 では正常に実行できる }
      WriteLn(String(PWideChar(TextRec(File1).FullName)));
      WriteLn('フルパスでファイルのオープンが成功しました(ロングパス設定が有効)');
      {$ENDIF}
    except
      on Ex: EOSError do
      begin
        WriteLn(StdErr, '*** OSエラー(', Ex.ErrorCode, ') : ', Ex.Message);
      end;
      on Ex: EInOutError do
      begin
        WriteLn(StdErr, '*** I/Oエラー(', Ex.ErrorCode, ') : ', Ex.Message);
      end;
      on Ex: Exception do
      begin
        WriteLn(StdErr, '*** エラー : ', Ex.Message);
      end;
    end;
  finally
    { オープンしたファイルをクローズ }
    if FH <> INVALID_HANDLE_VALUE then
    begin
      CloseHandle(FH);
    end;
    if TextRec(File1).Mode <> fmClosed then
    begin
      CloseFile(File1);
    end;
    WriteLn;
  end;
end.


 マニフェスト : app.manifest
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="e-hiyori.org.ManifestDemo4"
    version="1.0.0.0"
    processorArchitecture="*"
  />
  <description>Windows Application.</description>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        processorArchitecture="*"
        publicKeyToken="6595b64144ccf1df"
        language="*"
      />
    </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
    </application>
  </compatibility>
  <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>True/PM_V2</dpiAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">
      <disableWindowFiltering>True</disableWindowFiltering>
      <printerDriverIsolation>True</printerDriverIsolation>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
      <dpiAwareness>PerMonitorV2, PerMonitor</dpiAwareness>
      <longPathAware>True</longPathAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
      <activeCodePage>UTF-8</activeCodePage>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>


 リソースファイル : Manifest.rc
/////////////////////////////////////////////////////////////////////////////
//
// 本ファイルのコードページ
//

#pragma code_page(65001)    // Free Pascalの{$CODEPAGE UTF8}と同じようなもの。

/////////////////////////////////////////////////////////////////////////////
//
// アプリケーションのマニフェストを設定する。
//

#define CREATEPROCESS_MANIFEST_RESOURCE_ID  1
#define RT_MANIFEST                         24

// GUIモード  (CUIモードでも利用可)
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app.manifest"

// CUIモード  (GUIモードのみに必要な情報を削除)
// CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "console.manifest"


ManifestDemo4.pas コンパイルして ManifestDemo4.exe を作成します。


C:\PG\FreePascal\ManifestDemo_003>fpcrc64.cmd ManifestDemo4.pas
Free Pascal Compiler version 3.2.2 [2021/05/15] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling ManifestDemo4.pas
Compiling resource C:\PG\FreePascal\ManifestDemo_004\Manifest.rc
Compiling resource ManifestDemo4.obj
Linking ManifestDemo4.exe
175 lines compiled, 0.2 sec, 89872 bytes code, 5348 bytes data


ManifestDemo4.exe を実行すると Windows API のファイル操作で長いパス名が有効になっていることがわかります。

「(7)」で、Free Pascal 3.2.2 の標準関数が例外を発生します(想定した例外)。長いパス名が使えないことがわかります。

「(1)」「(2)」では、長くない相対パスで Free Pascal 3.2.2 の標準関数を使用しているので例外は発生しません。



MAX_PATH           : 260
TextRecNameLength  : 256

起点のディレクトリ : C:\PG\Test

(1) 起点のディレクトリ下にサブディレクトリ(A〜D)を作成しそのサブディレクトリをカレントディレクトリとする
A : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
B : BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
C : CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
D : DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD

(2) 標準手続き(AssignFile)でテスト用ファイルの相対パス名(<256)を設定
<<< file1内のファイルパス名(name) >>>
TestFile.txt

(3) 標準手続き(Rewrite)でテスト用ファイルTestFile.txtをサブディレクトリ下に作成
ファイルの作成が成功しました

(4) ファイルのフルパス名(起点のディレクトリ名+サブディレクトリ名(A〜D)+ファイル名)を表示
C:\PG\Test\AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\TestFile.txt

(5) Windows API(CreateFileW)でファイルのフルパス名を指定してオープン
フルパスでファイルのオープンが成功しました(ロングパス設定が有効)

(6) 標準手続き(AssignFile)でファイルのフルパス(>=256)を設定 - 全部は入らない
<<< file1内のファイルパス名(name) >>>
C:\PG\Test\AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\D

(7) 標準手続き(Reset)でファイルをオープン - Free Pascal 3.2.2 では上記の理由(パス不完全)でエラーになる(想定済)
*** I/Oエラー(2) : File not found



【参考』マニフェストを指定しない場合の実行結果


「(1)」のサブフォルダを作成する過程でパスの長さが MAX_PATH を超えたため例外が発生しています。



MAX_PATH           : 260
TextRecNameLength  : 256

起点のディレクトリ : C:\PG\Test

(1) 起点のディレクトリ下にサブディレクトリ(A〜D)を作成しそのサブディレクトリをカレントディレクトリとする
A : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
B : BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
C : CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CreateDir(NewDir)
*** OSエラー(3) : System error, (OS Code 3):
指定されたパスが見つかりません。





デモ 5. Windowsの既定のコードページ設定検証デモ


マニフェストで「<activeCodePage>UTF-8</activeCodePage>」を設定すると、アプリのプロセスに対してWindowsの既定のANSIコードページが UTF-8(65001) になります。ANSI系Windows APIの引数や戻り値も UTF-8 になります。マニフェストを指定しない場合、日語Windows(ja_JP)では既定のANSIコードページは Shift_JIS(932) です。これは当該プロセスに対して設定されるもので、Windows全体の設定が変わるものではありません。また、他のプロセスにも影響しません。

Windows API以外のサードパーティ製品のAPIなどについては、それぞれの仕様に準じます。

Windows APIの「GetACP」関数は、ANSIコードページ番号を返します。マニフェストを設定しないと932、設定すると65001を返します。プログラムでGetACPの値を調べることによりANSIコードページ番号を知ることができます。


「𠮷野家」の"𠮷"(俗にいう つちよし)は Shift_JIS では表すことができません。ユニコード(UTF-8,UTF-16,UTF-32)で表すことができます。

Wide系Windows APIはUTF-16(1200)でやりとりするので既定のANSIコードページやマニフェストの影響は受けません。


俗にいう つちよし は、𠮷 普通の よし は、


ファイル名にこの"𠮷"(俗にいう つちよし)を設定してアクセス検証します。


デモ 5.1 ANSI系Windows APIの検証デモ


マニフェストで「<activeCodePage>UTF-8</activeCodePage>」を設定したときの ANSI系Windows APIの動作検証をします。

プログラムファイルは以下のセットです。同一ディレクトリに置いてください。
ファイルはコードページ UTF-8(65001)で作成してください。(𠮷野家.txtはファイルの内容は問いません)

  • ManifestDemo5A.pas

  • appA.manifest

  • ManifestA.rc

  • 𠮷野家.txt


 ANSI系Windows APIの検証デモ : ManifestDemo5A.pas
(*****************************************************************************)
(* プログラム - ManifestDemo5A                                               *)
(*   マニフェストによるアクティブコードページのUTF-8設定の検証(ANSI系API)    *)
(*    - 日本語Windows(ja-JP)では既定のコードページはSJIS(Shift_JIS)          *)
(*    - ANSI系APIは設定されたアクティブコードページの影響を受ける            *)
(*****************************************************************************)
program ManifestDemo5A;

{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
{$WARN 4104 OFF}  (* UnicodeString <- AansiString   *)
{$WARN 4105 OFF}  (* AnsiString    <- UnicodeString *)

uses
  Windows, SysUtils;

{$R ManifestA.rc} (* この設定を外すとMessageBoxAやCreateFileAは正しく動作しない *)

(*****************************************************************************)
(* プログラムブロック - 宣言部                                               *)
(*****************************************************************************)

{ 定数 }
const
  FILENAME = '𠮷野家.txt';

{ 変数 }
var
  FH  : HANDLE;
  FN  : String;
  Msg : String;
  Cap : String;

(*****************************************************************************)
(* プログラムブロック - 実行文部                                             *)
(*****************************************************************************)
begin
  { Manifestで「UTF-8」の設定があれば次の2行は不要(CP_UTF8が設定される)。あっても良い }
  SetMultiByteConversionCodePage(CP_UTF8);
  SetMultiByteRTLFileSystemCodePage(CP_UTF8);
  FH  := INVALID_HANDLE_VALUE;
  FN  := ConcatPaths([ExtractFileDir(ParamStr(0)), FILENAME]);
  Msg := 'デモプログラム';
  Cap := 'Windowsコードページ : ' + GetACP.ToString;
  try
    try
      WriteLn;
      WriteLn('ANSI系Windows API(MessageBoxA,CreateFileA)使用');
      WriteLn;
      WriteLn('コードページ情報');
      WriteLn('GetACP       : ', GetACP, ' - WindowsのANSIコードページ');
      WriteLn('メッセージ   : ', StringCodepage(Msg));
      WriteLn('キャプション : ', StringCodepage(Cap));
      WriteLn('ファイル名   : ', StringCodepage(FN));
      { ANSI系APIはGetACPのコードページを使用するので文字列のコードページもGetACPと同じである必要がある }
      WriteLn;
      WriteLn('メッセージボックスの表示内容を確認して[OK]ボタンを押してください');
      Write('MessageBoxA実行');
      MessageBoxA(0, PChar(Msg), PChar(Cap), MB_OK);  { WinAPIのAnsi系 }
      WriteLn(' -> 終了しました');
      WriteLn;
      Write('CreateFileA実行');
      FH := CreateFileA(PChar(FN), GENERIC_READ, FILE_SHARE_READ, Nil, OPEN_EXISTING, 0, 0);
      if FH = INVALID_HANDLE_VALUE then
      begin
        WriteLn(' -> 例外発生');
        RaiseLastOSError; { EOSErrorをスロー }
      end;
      WriteLn(' -> ファイルのオープンが成功しました');
    except
      on Ex: EOSError do
      begin
        WriteLn(StdErr, '*** OSエラー(', Ex.ErrorCode, ') : ', Ex.Message);
      end;
      on Ex: Exception do
      begin
        WriteLn(StdErr, '*** エラー : ', Ex.Message);
      end;
    end;
  finally
    if FH <> INVALID_HANDLE_VALUE then
    begin
      CloseHandle(FH);
    end;
    WriteLn;
  end;
end.


 マニフェスト : appA.manifest
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="e-hiyori.org.ManifestDemo5A"
    version="1.0.0.0"
    processorArchitecture="*"
  />
  <description>Windows Application.</description>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        processorArchitecture="*"
        publicKeyToken="6595b64144ccf1df"
        language="*"
      />
    </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
    </application>
  </compatibility>
  <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>True/PM_V2</dpiAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">
      <disableWindowFiltering>True</disableWindowFiltering>
      <printerDriverIsolation>True</printerDriverIsolation>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
      <dpiAwareness>PerMonitorV2, PerMonitor</dpiAwareness>
      <longPathAware>True</longPathAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
      <activeCodePage>UTF-8</activeCodePage>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>


 リソースファイル : ManifestA.rc
/////////////////////////////////////////////////////////////////////////////
//
// 本ファイルのコードページ
//

#pragma code_page(65001)    // Free Pascalの{$CODEPAGE UTF8}と同じようなもの。

/////////////////////////////////////////////////////////////////////////////
//
// アプリケーションのマニフェストを設定する。
//

#define CREATEPROCESS_MANIFEST_RESOURCE_ID  1
#define RT_MANIFEST                         24

// GUIモード  (CUIモードでも利用可)
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "appA.manifest"

// CUIモード  (GUIモードのみに必要な情報を削除)
// CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "consoleW.manifest"


ManifestDemo5A.pas コンパイルして ManifestDemo5A.exe を作成します。


C:\PG\FreePascal\ManifestDemo_003>fpcrc64.cmd ManifestDemo5A.pas
Free Pascal Compiler version 3.2.2 [2021/05/15] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling ManifestDemo5A.pas
Compiling resource C:\PG\FreePascal\ManifestDemo_005\ManifestA.rc
Compiling resource ManifestDemo5A.obj
Linking ManifestDemo5A.exe
88 lines compiled, 0.2 sec, 75680 bytes code, 5300 bytes data


ManifestDemo5A.exe を実行すると Windows API の MessageBoxA でメッセージボックスを表示します。

[OK]ボタンで閉じると Windows API の CreateFileA で「𠮷野家.txt」ファイルをオーブンします。




ANSI系Windows API(MessageBoxA,CreateFileA)使用

コードページ情報
GetACP       : 65001 - WindowsのANSIコードページ
メッセージ   : 65001
キャプション : 65001
ファイル名   : 65001

メッセージボックスの表示内容を確認して[OK]ボタンを押してください
MessageBoxA実行 -> 終了しました

CreateFileA実行 -> ファイルのオープンが成功しました


GetACPの値もプログラムの文字列のコードページも65001で一致しているので、メッセージボックスも正しく表示され、「𠮷野家.txt」のオープンも成功するわけです。


【参考』マニフェストを指定しない場合の実行結果




ANSI系Windows API(MessageBoxA,CreateFileA)使用

コードページ情報
GetACP       : 932 - WindowsのANSIコードページ
メッセージ   : 65001
キャプション : 65001
ファイル名   : 65001

メッセージボックスの表示内容を確認して[OK]ボタンを押してください
MessageBoxA実行 -> 終了しました

CreateFileA実行 -> 例外発生
*** OSエラー(2) : System error, (OS Code 2):
指定されたファイルが見つかりません。


GetACPの値は932でプログラムの文字列のコードページが65001となり一致していないので、メッセージボックスは文字化けし、「𠮷野家.txt」の認識もできずオープンが失敗するわけです。


デモ 5.2 Wide系Windows APIの検証デモ


マニフェストで「<activeCodePage>UTF-8</activeCodePage>」を設定したときの Wide系Windows APIの動作検証をします。

プログラムファイルは以下のセットです。同一ディレクトリに置いてください。
ファイルはコードページ UTF-8(65001)で作成してください。(𠮷野家.txtは内容は問いません)

・ManifestDemo5W.pas
・appW.manifest
・ManifestW.rc
・𠮷野家.txt


 Wide系Windows APIの検証デモ : ManifestDemo5W.pas
(*****************************************************************************)
(* プログラム - ManifestDemo5W                                               *)
(*   マニフェストによるアクティブコードページのUTF-8設定の検証(Wide系API)    *)
(*    - 日本語Windows(ja-JP)では既定のコードページはSJIS(Shift_JIS)          *)
(*    - Wide系APIは設定されたアクティブコードページの影響を受けない          *)
(*    - 既定のANSIコードページに関係なくWide文字UTF-16が使用される           *)
(*****************************************************************************)
program ManifestDemo5W;

{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
{$WARN 4104 OFF}  (* UnicodeString <- AansiString   *)
{$WARN 4105 OFF}  (* AnsiString    <- UnicodeString *)

uses
  Windows, SysUtils;

{$R ManifestW.rc}  (* ManifestがなくてもMessageBoxWやCreateFileWは正しく動作 *)

(*****************************************************************************)
(* プログラムブロック - 宣言部                                               *)
(*****************************************************************************)

{ 定数 }
const
  FILENAME = '𠮷野家.txt';

{ 変数 }
var
  FH  : HANDLE;
  FN  : UnicodeString;
  Msg : UnicodeString;
  Cap : UnicodeString;

(*****************************************************************************)
(* プログラムブロック - 実行文部                                             *)
(*****************************************************************************)
begin
  { Manifestで「UTF-8」の設定があれば次の2行は不要(CP_UTF8が設定される)。あっても良い }
  SetMultiByteConversionCodePage(CP_UTF8);
  SetMultiByteRTLFileSystemCodePage(CP_UTF8);
  FH  := INVALID_HANDLE_VALUE;
  FN  := ConcatPaths([ExtractFileDir(ParamStr(0)), FILENAME]);
  Msg := 'デモプログラム';
  Cap := 'Windowsコードページ : ' + GetACP.ToString;
  try
    try
      WriteLn;
      WriteLn('Wide系Windows API(MessageBoxW,CreateFileW)使用');
      WriteLn;
      WriteLn('コードページ情報');
      WriteLn('GetACP       : ', GetACP, ' - WindowsのANSIコードページ');
      WriteLn('メッセージ   : ', StringCodepage(Msg));
      WriteLn('キャプション : ', StringCodepage(Cap));
      WriteLn('ファイル名   : ', StringCodepage(FN));
      { Wide系APIはUTF-16を使用するのでGetACPには左右されない }
      WriteLn;
      WriteLn('メッセージボックスの表示内容を確認して[OK]ボタンを押してください');
      Write('MessageBoxW実行');
      MessageBoxW(0, PWideChar(Msg), PWideChar(Cap), MB_OK);
      WriteLn(' -> 終了しました');
      WriteLn;
      Write('CreateFileW実行');
      FH := CreateFileW(PWideChar(FN), GENERIC_READ, FILE_SHARE_READ, Nil, OPEN_EXISTING, 0, 0);
      if FH = INVALID_HANDLE_VALUE then
      begin
        WriteLn(' -> 例外発生');
        RaiseLastOSError; { EOSErrorをスロー }
      end;
      WriteLn(' -> ファイルのオープンが成功しました。');
    except
      on Ex: EOSError do
      begin
        WriteLn(StdErr, '*** OSエラー(', Ex.ErrorCode, ') : ', Ex.Message);
      end;
      on Ex: Exception do
      begin
        WriteLn(StdErr, '*** エラー : ', Ex.Message);
      end;
    end;
  finally
    if FH <> INVALID_HANDLE_VALUE then
    begin
      CloseHandle(FH);
    end;
    WriteLn;
  end;
end.


 マニフェスト : appW.manifest
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="e-hiyori.org.ManifestDemo5W"
    version="1.0.0.0"
    processorArchitecture="*"
  />
  <description>Windows Application.</description>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        processorArchitecture="*"
        publicKeyToken="6595b64144ccf1df"
        language="*"
      />
    </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
    </application>
  </compatibility>
  <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>True/PM_V2</dpiAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">
      <disableWindowFiltering>True</disableWindowFiltering>
      <printerDriverIsolation>True</printerDriverIsolation>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
      <dpiAwareness>PerMonitorV2, PerMonitor</dpiAwareness>
      <longPathAware>True</longPathAware>
    </asmv3:windowsSettings>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
      <activeCodePage>UTF-8</activeCodePage>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>


 リソースファイル : ManifestA.rc
/////////////////////////////////////////////////////////////////////////////
//
// 本ファイルのコードページ
//

#pragma code_page(65001)    // Free Pascalの{$CODEPAGE UTF8}と同じようなもの。

/////////////////////////////////////////////////////////////////////////////
//
// アプリケーションのマニフェストを設定する。
//

#define CREATEPROCESS_MANIFEST_RESOURCE_ID  1
#define RT_MANIFEST                         24

// GUIモード  (CUIモードでも利用可)
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "appW.manifest"

// CUIモード  (GUIモードのみに必要な情報を削除)
// CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "consoleW.manifest"


ManifestDemo5W.pas コンパイルして ManifestDemo5W.exe を作成します。


C:\PG\FreePascal\ManifestDemo_003>fpcrc64.cmd ManifestDemo5W.pas
Free Pascal Compiler version 3.2.2 [2021/05/15] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling ManifestDemo5W.pas
Compiling resource C:\PG\FreePascal\ManifestDemo_005\ManifestW.rc
Compiling resource ManifestDemo5W.obj
Linking ManifestDemo5W.exe
89 lines compiled, 0.2 sec, 75680 bytes code, 5300 bytes data


ManifestDemo5W.exe を実行すると Windows API の MessageBoxW でメッセージボックスを表示します。

[OK]ボタンで閉じると Windows API の CreateFileW で「𠮷野家.txt」ファイルをオーブンします。




Wide系Windows API(MessageBoxW,CreateFileW)使用

コードページ情報
GetACP       : 65001 - WindowsのANSIコードページ
メッセージ   : 1200
キャプション : 1200
ファイル名   : 1200

メッセージボックスの表示内容を確認して[OK]ボタンを押してください
MessageBoxW実行 -> 終了しました

CreateFileW実行 -> ファイルのオープンが成功しました。


Wide系Windows APIもプログラムの文字列もGetACPの値(ANSIコードページ)と関係なくUTF-16(1200)で一致するので、メッセージボックスも正しく表示され、「𠮷野家.txt」のオープンも成功するわけです。


【参考』マニフェストを指定しない場合の実行結果


メッセージボックスのキャプションに表示されるコードページ番号とGetACPの番号が違うだけで、あとはマニフェストを指定した場合と同じです。




Wide系Windows API(MessageBoxW,CreateFileW)使用

コードページ情報
GetACP       : 932 - WindowsのANSIコードページ
メッセージ   : 1200
キャプション : 1200
ファイル名   : 1200

メッセージボックスの表示内容を確認して[OK]ボタンを押してください
MessageBoxW実行 -> 終了しました

CreateFileW実行 -> ファイルのオープンが成功しました。





5. ダウンロード


本記事のプログラムコードなどは以下のページでダウンロードできます。


Object Pascal 備忘録




6. 参照


Free Pascal コンパイル環境

バージョン情報を設定する

アプリのアイコンを設定する



[ライセンスについて]