Skip to content

Instantly share code, notes, and snippets.

@uemuraj
Last active October 11, 2022 04:19
Show Gist options
  • Save uemuraj/404e864f0ae9bc27a7b307d6a794f450 to your computer and use it in GitHub Desktop.
Save uemuraj/404e864f0ae9bc27a7b307d6a794f450 to your computer and use it in GitHub Desktop.
ISO ファイルをマウントしてプログラムから使用する。
#define INITGUID
#include <Windows.h>
#include <virtdisk.h>
#include <locale>
#include <iostream>
#include <filesystem>
#include <system_error>
class VirtualDisk
{
HANDLE m_handle;
public:
VirtualDisk(const std::filesystem::path & path) : m_handle{}
{
constexpr auto flag = OPEN_VIRTUAL_DISK_FLAG_NONE;
constexpr auto mask = VIRTUAL_DISK_ACCESS_ATTACH_RO | VIRTUAL_DISK_ACCESS_DETACH | VIRTUAL_DISK_ACCESS_GET_INFO;
VIRTUAL_STORAGE_TYPE type{ VIRTUAL_STORAGE_TYPE_DEVICE_ISO, VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN };
if (auto errocode = ::OpenVirtualDisk(&type, std::filesystem::absolute(path).c_str(), mask, flag, nullptr, &m_handle); errocode != ERROR_SUCCESS)
{
throw std::system_error(errocode, std::system_category(), __FUNCTION__);
}
}
~VirtualDisk() noexcept
{
::CloseHandle(m_handle);
}
operator HANDLE() const
{
return m_handle;
}
};
class AttachedVirtualDisk
{
const VirtualDisk & m_disk;
public:
AttachedVirtualDisk(const VirtualDisk & disk) : m_disk(disk)
{
constexpr auto flag = ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY | ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME;
ATTACH_VIRTUAL_DISK_PARAMETERS param{ ATTACH_VIRTUAL_DISK_VERSION_1 };
if (auto errcode = ::AttachVirtualDisk(m_disk, nullptr, flag, 0, &param, nullptr); errcode != ERROR_SUCCESS)
{
throw std::system_error(errcode, std::system_category(), __FUNCTION__);
}
}
~AttachedVirtualDisk()
{
constexpr auto flag = DETACH_VIRTUAL_DISK_FLAG_NONE;
if (auto errcode = ::DetachVirtualDisk(m_disk, flag, 0); errcode != ERROR_SUCCESS)
{
std::cerr << std::system_category().message(errcode) << std::endl;
}
}
operator std::filesystem::path() const
{
return GetDrivePath();
}
std::filesystem::path GetPhysicalPath() const
{
std::wstring buff(7, 0);
ULONG size = (buff.size() + 1) * sizeof(wchar_t);
if (auto errcode = ::GetVirtualDiskPhysicalPath(m_disk, &size, buff.data()); errcode == ERROR_SUCCESS)
{
return buff;
}
else if (errcode != ERROR_INSUFFICIENT_BUFFER)
{
throw std::system_error(errcode, std::system_category(), __FUNCTION__);
}
buff.resize(size / sizeof(wchar_t) - 1);
if (auto errcode = ::GetVirtualDiskPhysicalPath(m_disk, &size, buff.data()); errcode == ERROR_SUCCESS)
{
return buff;
}
else
{
throw std::system_error(errcode, std::system_category(), __FUNCTION__);
}
}
std::filesystem::path GetDrivePath() const
{
auto name = GetPhysicalPath().stem();
DWORD index = 0, drives = ::GetLogicalDrives();
while (BitScanForward(&index, drives))
{
wchar_t root[] = { (wchar_t) (L'A' + index), L':', L'\0', L'\0' };
wchar_t buff[MAX_PATH]{};
if (::QueryDosDevice(root, buff, _countof(buff)) == 0)
{
throw std::system_error(::GetLastError(), std::system_category(), __FUNCTION__);
}
auto device = std::filesystem::path(buff).stem();
if (_wcsicmp(device.c_str(), name.c_str()) == 0)
{
root[2] = std::filesystem::path::preferred_separator;
return root;
}
BitTestAndReset((LONG *) &drives, index);
}
throw std::system_error(ERROR_PATH_NOT_FOUND, std::system_category(), __FUNCTION__);
}
};
int wmain(int argc, wchar_t * argv[])
{
try
{
std::locale::global(std::locale(""));
if (argc > 1)
{
VirtualDisk iso(argv[1]);
AttachedVirtualDisk disk(iso);
for (const auto & entry : std::filesystem::directory_iterator(disk))
{
std::wcout << entry.path() << std::endl;
}
}
return 0;
}
catch (const std::exception & e)
{
std::cerr << e.what() << std::endl;
return 1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment