他人の空似自作物置場

AppContainerUtils.zip/TestSharedMemory1/TestSharedMemory/TestSharedMemory.cpp


#include <iostream>
#include <vector>
#include <string>
#include <sstream>

#include <boost/shared_ptr.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>

#include <Windows.h>
#include <Userenv.h>

#include "SharedStruct.h"

#pragma comment(lib, "Userenv.lib")

typedef boost::shared_ptr<boost::remove_pointer<PSID>::type> SHARED_SID;
void MyFreeSid(PSID sid) {
  if (sid != NULL) {
    ::FreeSid(sid);
  }
}
SHARED_SID ToSharedSID(PSID sid) {
  return SHARED_SID(sid, &MyFreeSid);
}

typedef boost::shared_ptr<boost::remove_pointer<HANDLE>::type> SHARED_HANDLE;
void MyCloseHandle(const HANDLE handle) {
  if (handle != NULL) {
    ::CloseHandle(handle);
  }
}

void MyDeleteProcThreadAttributeList(const LPPROC_THREAD_ATTRIBUTE_LIST attrList) {
  if (attrList != NULL) {
    ::DeleteProcThreadAttributeList(attrList);
  }
}
class DeleteAppContainer {
public:
  DeleteAppContainer(const wchar_t * const name) : name(name) { }
  ~DeleteAppContainer() {
    ::DeleteAppContainerProfile(name);
  }
private:
  const wchar_t * const name;
};

bool RunImpl(SHARED_HANDLE &processHandle, const SHARED_SID sid, const boost::filesystem::path &path, const HANDLE arg) {
  const unsigned int attrCount = 3;
  SIZE_T size;
  ::InitializeProcThreadAttributeList(NULL, attrCount, 0, &size);
  typedef boost::shared_ptr<boost::remove_pointer<LPPROC_THREAD_ATTRIBUTE_LIST>::type> SHARED_ATTR_LIST;
  const SHARED_ATTR_LIST attrList(reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(new unsigned char[size]), &MyDeleteProcThreadAttributeList);
  if (::InitializeProcThreadAttributeList(attrList.get(), attrCount, 0, &size) == FALSE) {
    return false;
  }
  SECURITY_CAPABILITIES sc;
  sc.AppContainerSid = sid.get();
  sc.Capabilities = NULL;
  sc.CapabilityCount = 0;
  sc.Reserved = 0;
  if (::UpdateProcThreadAttribute(attrList.get(), 0, PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, &sc, sizeof(sc), NULL, NULL) == FALSE) {
    return false;
  }
  STARTUPINFOEXW startupInfoEx = { 0 };
  startupInfoEx.StartupInfo.cb = sizeof(STARTUPINFOEXW); // StartupInfoのサイズではなくstartupInfoExのサイズである点に注意
  startupInfoEx.lpAttributeList = attrList.get();
  PROCESS_INFORMATION pi = { 0 };
  // ハンドルをコマンドライン引数で渡す
  std::wostringstream woss;
  woss << path.wstring() << L" " << reinterpret_cast<unsigned int>(arg);
  wchar_t buf[1024];
  ::wcscpy_s(buf, woss.str().c_str());
  // bInheritHandles = TRUEでハンドルを継承させる
  if (::CreateProcessW(path.wstring().c_str(), buf, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, reinterpret_cast<LPSTARTUPINFO>(&startupInfoEx), &pi) == FALSE) {
    return false;
  }
  processHandle.reset(pi.hProcess, &MyCloseHandle);
  ::CloseHandle(pi.hThread);
  return true;
}

bool Run(SHARED_HANDLE &processHandle, const wchar_t * const appContainerName, const boost::filesystem::path &path, const HANDLE arg) {
  PSID sidImpl;
  if (FAILED(::CreateAppContainerProfile(appContainerName, appContainerName, appContainerName, NULL, 0, &sidImpl))) {
    return false;
  }
  DeleteAppContainer deleteAppContainer(appContainerName);
  const SHARED_SID sid = ToSharedSID(sidImpl);
  if (!RunImpl(processHandle, sid, path, arg)) {
    return false;
  }
  return true;
}

SHARED_SID GetAppContainerSid(const wchar_t * const name) {
  PSID sidImpl;
  if (FAILED(::DeriveAppContainerSidFromAppContainerName(name, &sidImpl))) {
    return SHARED_SID();
  }
  return ToSharedSID(sidImpl);
}

bool RunExist(SHARED_HANDLE &processHandle, const wchar_t * const appContainerName, const boost::filesystem::path &path, const HANDLE arg) {
  const SHARED_SID sid = GetAppContainerSid(appContainerName);
  if (!sid) {
    return false;
  }
  if (!RunImpl(processHandle, sid, path, arg)) {
    return false;
  }
  return true;
}

bool GetSharedMemoryPtr(void *&ptr, const HANDLE handle) {
  ptr = ::MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  if (ptr == NULL) {
    return false;
  }
  return true;
}

bool CreateSharedMemory(HANDLE &handle, const wchar_t * const sharedMemoryName, const unsigned int sharedMemorySize) {
  // bInheritHandle = TRUEにすることでハンドルを継承可能にする
  SECURITY_ATTRIBUTES attr = {0};
  attr.nLength = sizeof(attr);
  attr.bInheritHandle = TRUE;
  attr.lpSecurityDescriptor = NULL;
  handle = ::CreateFileMappingW(INVALID_HANDLE_VALUE, &attr, PAGE_READWRITE, 0, sharedMemorySize, sharedMemoryName);
  if (handle == NULL) {
    return false;
  }
  return true;
}

int main(const unsigned int argc, const char * const * const argv) {
  std::locale::global(std::locale("japanese"));
  if (argc != 2) {
    std::wcout << L"usage: TestSharedMemory.exe exe_path" << std::endl;
    std::wcin.ignore();
    return 1;
  }
  const boost::filesystem::path path(argv[1]);
  if (!boost::filesystem::is_regular_file(path)) {
    std::wcout << L"Error: ファイルが見つかりませんでした" << std::endl;
    std::wcin.ignore();
    return 1;
  }
  const wchar_t * const appContainerName = L"AppConteinerTest";
  const wchar_t * const sharedMemoryName = L"AppConteinerTestMemory";
  HANDLE handle;
  if (!CreateSharedMemory(handle, sharedMemoryName, sizeof(SharedStruct))) {
    std::wcout << L"Error: 共有メモリーの生成に失敗しました" << std::endl;
    std::wcin.ignore();
    return 1;
  }
  void *ptr;
  if (!GetSharedMemoryPtr(ptr, handle)) {
    std::wcout << L"Error: 共有メモリーの取得に失敗しました" << std::endl;
    std::wcin.ignore();
    return 1;
  }
  SHARED_HANDLE processHandle;
  if (!Run(processHandle, appContainerName, path, handle)) {
    if (!RunExist(processHandle, appContainerName, path, handle)) {
      std::wcout << L"Error: アプリの起動に失敗しました" << std::endl;
      std::wcin.ignore();
      return 1;
    }
  }
  SharedStruct &sharedStruct = *reinterpret_cast<SharedStruct *>(ptr);
  while (::WaitForSingleObject(processHandle.get(), 100) == WAIT_TIMEOUT) {
    if (sharedStruct.changeFlag) {
      sharedStruct.changeFlag = false;
      std::wcout << sharedStruct.value << std::endl;
    }
  }
  return 0;
}