AppContainer関連API情報まとめ

AppContainer関連のAPIで調べたことについてまとめておく。
これらの情報は公式ではなく、あくまで自分が個人的に調べたものであるので間違っていている可能性があることに注意。
また、実際に動くコードや解説などが目的の人はAppContainerでデスクトップアプリを起動してみたAppContainer関連サンプル紹介を参照してほしい。

この記事の目次

公開API

CreateAppContainerProfile

MSDN参照

pszAppContainerNameの名前でAppContainerを作成する。
必要なくなったらDeleteAppContainerProfileで削除すること。
AppContainerRegisterSidと違いsidはシステム側で適切に生成してくれる様子。
すでに存在する場合は失敗する、生成済みかを判別する方法は特にない様子。
pszAppContainerNameはAppContainerRegisterSidでいうmonikerだと思われる。
pCapabilitiesは指定しなくともUpdateProcThreadAttributeで指定してあれば有効になる、というかpCapabilitiesを指定して何が変わるのかわからなかった、通常のモダンアプリなどを起動する際に付与するCapabilitiesを算出するためのものだろうか?
こちらはAppContainerRegisterSidと違ってMSDNにも載っておりsidの適切な生成などがあるので、一般にはこちらを使ってほしいという意図なのだと思われる。

サンプル

  const wchar_t * const name = L"AppConteinerTest";
  PSID sid;
  if (FAILED(::CreateAppContainerProfile(name, name, name, NULL, 0, &sid))) {
    return;
  }

DeleteAppContainerProfile

MSDN参照

指定したAppContainerを削除する。
GetAppContainerFolderPathで取得できるフォルダの中身や、GetAppContainerRegistryLocationで取得できるレジストリも消える。

サンプル

  const wchar_t * const name = L"AppConteinerTest";
  PSID sid;
  if (FAILED(::CreateAppContainerProfile(name, name, name, NULL, 0, &sid))) {
    return;
  }
  ...
  ::DeleteAppContainerProfile(name);

DeriveAppContainerSidFromAppContainerName

MSDN参照

pszAppContainerNameからCreateAppContainerProfile互換のsidを取得する。
AppContainerDeriveSidFromMonikerとほぼ同一の動作をする。
存在しないAppContainerに対しても実行でき、その場合はCreateAppContainerProfileで生成した場合に割り当てられるsidが返る。
取得したsidは必要なくなったらFreeSidで解放すること。

  PSID sid;
  if (FAILED(::DeriveAppContainerSidFromAppContainerName(name, &sid))) {
    return;
  }
  ...
  ::FreeSid(sid);

GetAppContainerFolderPath

MSDN参照

sidからアプリケーションフォルダを取得する。
アプリケーションフォルダ内はAppContainer下でも自由に読み書きでき、DeleteAppContainerProfileを呼び出さなければアプリ終了後にも残る。
逆にDeleteAppContainerProfileを呼ぶと、プロセスが生きていようともその時点でファイルが削除され読み書き権限もなくなる。
取得したpathは必要なくなったらCoTaskMemFreeで解放すること。
ちなみに手元だと
C:\Users\#{ユーザー名}\AppData\Local\Packages\#{AppContainer名}\AC
に保存されていた。

サンプル

  const wchar_t * const name = L"AppConteinerTest";
  PSID sid;
  if (FAILED(::CreateAppContainerProfile(name, name, name, NULL, 0, &sid))) {
    return;
  }
  wchar_t *sidStr;
  if (::ConvertSidToStringSidW(sid, &sidStr) == FALSE) {
    ::FreeSid(sid);
    return;
  }
  wchar_t *appContainerPath;
  if (FAILED(::GetAppContainerFolderPath(sidStr, &appContainerPath))) {
    ::FreeSid(sid);
    ::LocalFree(sidStr);
    return;
  }
  ...
  ::FreeSid(sid);
  ::LocalFree(sidStr);
  ::CoTaskMemFree(appContainerPath);

GetAppContainerRegistryLocation

MSDN参照

AppContainer下でも読み書きできるレジストリキーを取得する。
AppContainer下で実行されているプロセスでしか使えず、それ以外のプロセスで実行しても失敗する。
GetAppContainerFolderPathと同様にDeleteAppContainerProfileを呼び出さなければアプリ終了後にも残る。
逆にDeleteAppContainerProfileを呼ぶと、プロセスが生きていようともその時点でレジストリは削除され読み書き権限もなくなり、APIも失敗するようになる。
MSDNには記載がないが、おそらくRegCloseKeyで閉じる必要がある。
ちなみに、手元の環境だと
HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer\Storage\#{AppContainer名}.#{乱数と思われるもの}
に保存されていた。

サンプル

  HKEY key;
  if (FAILED(::GetAppContainerRegistryLocation(KEY_ALL_ACCESS, &key))) {
    return;
  }
  ...
  ::RegCloseKey(key);

GetAppContainerNamedObjectPath

MSDN参照

AppContainer内プロセスで作成した各種ハンドルのリダイレクト先パス名を取得する。
外部のプロセスからこのパス名を付けてハンドルを作成することでAppContainer内部とやり取りすることができる。
手元の環境で試した範囲では「AppContainerNamedObjects\#{AppContainerのSID}」と帰ってくるようだった。
WinObjで具体的にどこにハンドルが属しているかを見ることができるので、興味があるなら見るのもよい。
詳しくはAppContainer関連サンプル紹介を参照。

サンプル

  PSID sid;
  if (FAILED(::DeriveAppContainerSidFromAppContainerName(name, &sid))) {
    return;
  }
  wchar_t buffer[4096];
  ULONG size;
  if (::GetAppContainerNamedObjectPath(NULL, sid, _countof(buffer), buffer, &size) == FALSE) {
    return;
  }
  ...
  ::FreeSid(sid);

非公開API

使用は推奨されないが、一応非公開APIについても調べたので書いておく。

AppContainerRegisterSid

HRESULT WINAPI AppContainerRegisterSid(PSID sid, LPCWSTR moniker, LPCWSTR display_name);

非公開API、GetProcAddressして使う。
sidをAppContainerとして登録する。
必要なくなったらAppContainerUnregisterSidで削除すること。
CreateAppContainerProfileで作成した場合と違いアプリケーションフォルダやレジストリへのアクセス権限は付与されないので注意。
sidやmonikerがすでに存在する場合は失敗する、すでに存在するか調べたい場合はAppContainerLookupMonikerを使用すること。
win8だとkernel32.dllにいるが8.1でkernelbase.dllに移った、おそらくVirtulDllで何か仮想dllに紐づいていてその実態が移動したとかだと思われる。
ぐぐるとわかるのだがchromiumのソースで使われていたことがある、というかほかに情報がない。

サンプル

  const wchar_t * const appContainerSid = L"S-1-15-2-1234567890-1234567890-1234567890-123456789-1234567890-123456789-1234567890";
  const wchar_t * const name = L"AppConteinerTest";
  typedef HRESULT(WINAPI* AppContainerRegisterSidPtr)(PSID sid, LPCWSTR moniker, LPCWSTR display_name);
  AppContainerRegisterSidPtr AppContainerRegisterSid = reinterpret_cast<AppContainerRegisterSidPtr>(::GetProcAddress(::GetModuleHandleW(L"kernelbase.dll"), "AppContainerRegisterSid"));
  if (AppContainerRegisterSid == NULL) {
    AppContainerRegisterSid = reinterpret_cast<AppContainerRegisterSidPtr>(::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "AppContainerRegisterSid"));
    if (AppContainerRegisterSid == NULL) {
      return false;
    }
  }
  PSID sid;
  if (::ConvertStringSidToSidW(appContainerSid, &sid) == FALSE) {
    return false;
  }
  if (FAILED(AppContainerRegisterSid(sid, name, name))) {
    return false;
  }

AppContainerUnregisterSid

HRESULT WINAPI AppContainerUnregisterSid(PSID sid);

非公開API、GetProcAddressして使う。
sidでAppContainerに登録されている情報を削除する。
AppContainerRegisterSidと同様にwin8だとkernel32.dllにいるが8.1でkernelbase.dllに移った。

サンプル

  typedef HRESULT(WINAPI* AppContainerUnregisterSidPtr)(PSID sid);
  AppContainerUnregisterSidPtr AppContainerUnregisterSid = reinterpret_cast<AppContainerUnregisterSidPtr>(::GetProcAddress(::GetModuleHandleW(L"kernelbase.dll"), "AppContainerUnregisterSid"));
  if (AppContainerUnregisterSid == NULL) {
    AppContainerUnregisterSid = reinterpret_cast<AppContainerUnregisterSidPtr>(::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "AppContainerUnregisterSid"));
    if (AppContainerUnregisterSid == NULL) {
      return;
    }
  }
  AppContainerUnregisterSid(sid);

AppContainerLookupMoniker

HRESULT WINAPI AppContainerLookupMoniker(PSID sid, LPWSTR* moniker);

非公開API、GetProcAddressして使う。
sidで登録されているAppContainerのmonikerを取得する。
sidに紐づくAppContainerが存在しない場合は失敗する。
monikerにはAPI内で動的に確保されたメモリーが割り当てられるため、必要なくなったらAppContainerFreeMemoryで解放すること。
AppContainerRegisterSidと同様にwin8だとkernel32.dllにいるが8.1でkernelbase.dllに移った。

サンプル

  typedef HRESULT(WINAPI* AppContainerLookupMonikerPtr)(PSID sid, LPWSTR* moniker);
  AppContainerLookupMonikerPtr AppContainerLookupMoniker = reinterpret_cast<AppContainerLookupMonikerPtr>(::GetProcAddress(::GetModuleHandleW(L"kernelbase.dll"), "AppContainerLookupMoniker"));
  if (AppContainerLookupMoniker == NULL) {
    AppContainerLookupMoniker = reinterpret_cast<AppContainerLookupMonikerPtr>(::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "AppContainerLookupMoniker"));
    if (AppContainerLookupMoniker == NULL) {
      return;
    }
  }
  typedef BOOLEAN(WINAPI* AppContainerFreeMemoryPtr)(void* ptr);
  AppContainerFreeMemoryPtr AppContainerFreeMemory = reinterpret_cast<AppContainerFreeMemoryPtr>(::GetProcAddress(::GetModuleHandleW(L"kernelbase.dll"), "AppContainerFreeMemory"));
  if (AppContainerFreeMemory == NULL) {
    AppContainerFreeMemory = reinterpret_cast<AppContainerFreeMemoryPtr>(::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "AppContainerFreeMemory"));
    if (AppContainerFreeMemory == NULL) {
      return;
    }
  }
  wchar_t *moniker;
  if (FAILED(AppContainerLookupMoniker(sid, &moniker))) {
    return;
  }
  ...
  AppContainerFreeMemory(moniker);

AppContainerDeriveSidFromMoniker

HRESULT WINAPI AppContainerDeriveSidFromMoniker(LPCWSTR moniker, PSID *sid);

非公開API、GetProcAddressして使う。
monikerからCreateAppContainerProfile互換のsidを取得する。
存在しないAppContainerに対しても実行でき、その場合はCreateAppContainerProfileで生成した場合に割り当てられるsidが返る。
どうやらmonikerをハッシュ関数に食わせるなどで生成しているようで、AppContainerRegisterSidで登録したmonikerを指定してもまるで違うsidが返ってくるので注意。
取得したsidは必要なくなったらAppContainerFreeMemoryで解放すること。
AppContainerRegisterSidと同様にwin8だとkernel32.dllにいるが8.1でkernelbase.dllに移った。

  typedef HRESULT(WINAPI* AppContainerDeriveSidFromMonikerPtr)(LPCWSTR moniker, PSID *sid);
  AppContainerDeriveSidFromMonikerPtr AppContainerDeriveSidFromMoniker = reinterpret_cast<AppContainerDeriveSidFromMonikerPtr>(::GetProcAddress(::GetModuleHandleW(L"kernelbase.dll"), "AppContainerDeriveSidFromMoniker"));
  if (AppContainerDeriveSidFromMoniker == NULL) {
    AppContainerDeriveSidFromMoniker = reinterpret_cast<AppContainerDeriveSidFromMonikerPtr>(::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "AppContainerDeriveSidFromMoniker"));
    if (AppContainerDeriveSidFromMoniker == NULL) {
      return;
    }
  }
  PSID sid;
  if (FAILED(AppContainerDeriveSidFromMoniker(moniker, &sid))) {
    return;
  }
  ...
  AppContainerFreeMemory(sid);

AppContainerFreeMemory

BOOLEAN WINAPI AppContainerFreeMemory(void* ptr);

非公開API、GetProcAddressして使う。
AppContainer関連APIで確保したメモリーを開放する。
AppContainerRegisterSidと同様にwin8だとkernel32.dllにいるが8.1でkernelbase.dllに移った。

サンプル

  typedef BOOLEAN(WINAPI* AppContainerFreeMemoryPtr)(void* ptr);
  AppContainerFreeMemoryPtr AppContainerFreeMemory = reinterpret_cast<AppContainerFreeMemoryPtr>(::GetProcAddress(::GetModuleHandleW(L"kernelbase.dll"), "AppContainerFreeMemory"));
  if (AppContainerFreeMemory == NULL) {
    AppContainerFreeMemory = reinterpret_cast<AppContainerFreeMemoryPtr>(::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "AppContainerFreeMemory"));
    if (AppContainerFreeMemory == NULL) {
      return;
    }
  }
  AppContainerFreeMemory(ptr);

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です