I am trying to mount iso file with python on Windows 10. Here is the code:
import ctypes
from ctypes import wintypes
ByteArray8 = wintypes.BYTE * 8
src = r'F:\Backup\ubuntu.iso'
class GUID(ctypes.Structure):
_fields_ = [
("Data1", ctypes.c_long),
("Data2", ctypes.c_short),
("Data3", ctypes.c_short),
("Data4", ByteArray8)
]
guid = GUID(0xec984aec, 0xa0f9, 0x47e9, ByteArray8(0x90, 0x1f, 0x71, 0x41, 0x5a, 0x66, 0x34, 0x5b))
class VIRTUAL_STORAGE_TYPE(ctypes.Structure):
_fields_ = [
('DeviceId', ctypes.c_ulong),
('VendorId', GUID)
]
virtual_storage_type = VIRTUAL_STORAGE_TYPE(1, guid)
handle = wintypes.HANDLE()
Path = ctypes.c_wchar_p(src)
print(
ctypes.windll.virtdisk.OpenVirtualDisk(
ctypes.byref(virtual_storage_type),
Path,
0x000d0000,
0x00000000,
None,
ctypes.byref(handle)
)
)
print(
ctypes.windll.virtdisk.AttachVirtualDisk(
handle,
None,
0x00000001,
0,
None,
None
)
)
It shows two 0 after run, which means the open and attach operation succeed. But no new driver shown in explorer.
I want to know the reason and how to mount .iso file correctly. Here is reference: https://learn.microsoft.com/en-us/windows/win32/api/virtdisk/nf-virtdisk-openvirtualdisk https://learn.microsoft.com/en-us/windows/win32/api/virtdisk/nf-virtdisk-attachvirtualdisk
2 problems with the code:
Functional. By default, disk is closed when its corresponding handle is (which happens automatically when the program ends). So, the disk was opened (and shown in Explorer), but only for a very short period of time (after the AttachVirtualDisk call till program end), so you were not able to see it. To be able to use the disk, either:
Don't stop the program until you're done using the disk (add an input statement at the very end)
Detach the disk lifetime from its handle's one (use ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME flag from [MS.Learn]: ATTACH_VIRTUAL_DISK_FLAG enumeration (virtdisk.h)).
Needless to say that now, you'll have to detach the disk yourself, by either:
Eject it from Explorer
Enhancing code to call DetachVirtualDisk
Also, not sure what are the implications of repeatedly attaching the disk (without detaching it)
Coding - Undefined Behavior generator. Check [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer) for a common pitfall when working with CTypes (calling functions)
code00.py:
#!/usr/bin/env python
import ctypes as cts
import sys
from ctypes import wintypes as wts
class GUID(cts.Structure):
_fields_ = (
("Data1", cts.c_ulong),
("Data2", cts.c_ushort),
("Data3", cts.c_ushort),
("Data4", cts.c_ubyte * 8),
)
class VIRTUAL_STORAGE_TYPE(cts.Structure):
_fields_ = (
("DeviceId", wts.ULONG),
("VendorId", GUID),
)
ERROR_SUCCESS = 0
VIRTUAL_STORAGE_TYPE_DEVICE_ISO = 1
VIRTUAL_DISK_ACCESS_READ = 0x000D0000
OPEN_VIRTUAL_DISK_FLAG_NONE = 0x00000000
ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY = 0x00000001
ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME = 0x00000004
VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT = GUID(0xEC984AEC, 0xA0F9, 0x47E9, (0x90, 0x1F, 0x71, 0x41, 0x5A, 0x66, 0x34, 0x5B))
def main(*argv):
path = r"l:\Kit\Linux\Ubuntu\pc064\20\ubuntu-20.04.1-desktop-amd64.iso"
virtdisk = cts.WinDLL("VirtDisk")
OpenVirtualDisk = virtdisk.OpenVirtualDisk
OpenVirtualDisk.argtypes = (cts.POINTER(VIRTUAL_STORAGE_TYPE), cts.c_wchar_p, cts.c_int, cts.c_int, cts.c_void_p, wts.HANDLE)
OpenVirtualDisk.restype = wts.DWORD
AttachVirtualDisk = virtdisk.AttachVirtualDisk
AttachVirtualDisk.argtypes = (wts.HANDLE, cts.c_void_p, cts.c_int, wts.ULONG, cts.c_void_p, cts.c_void_p)
AttachVirtualDisk.restype = wts.DWORD
kernel32 = cts.WinDLL("Kernel32.dll")
GetLastError = kernel32.GetLastError
GetLastError.argtypes = ()
GetLastError.restype = wts.DWORD
CloseHandle = kernel32.CloseHandle
CloseHandle.argtypes = (wts.HANDLE,)
CloseHandle.restype = wts.BOOL
vts = VIRTUAL_STORAGE_TYPE(VIRTUAL_STORAGE_TYPE_DEVICE_ISO, VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT)
handle = wts.HANDLE()
res = OpenVirtualDisk(cts.byref(vts), path, VIRTUAL_DISK_ACCESS_READ, OPEN_VIRTUAL_DISK_FLAG_NONE, None, cts.byref(handle))
if res != ERROR_SUCCESS:
print(f"OpenVirtualDisk error: {GetLastError()}")
return -1
attach_flags = ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY
permanent = bool(argv) # Any argument was passed
if permanent:
attach_flags |= ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME
res = AttachVirtualDisk(handle, None, attach_flags, 0, None, None)
if res != ERROR_SUCCESS:
print(f"AttachVirtualDisk error: {GetLastError()}")
CloseHandle(handle)
return -2
input(f"Press <Enter> to continue{'' if permanent else ' (this also closes the ISO drive)'} ...")
CloseHandle(handle) # Performed automatically
if __name__ == "__main__":
print(
"Python {:s} {:03d}bit on {:s}\n".format(
" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32,
sys.platform,
)
)
rc = main(*sys.argv[1:])
print("\nDone.\n")
sys.exit(rc)
Output:
[cfati@CFATI-5510-0:e:\Work\Dev\StackExchange\StackOverflow\q078246936]> sopr.bat ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" ./code00.py Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr 5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] 064bit on win32 Press <Enter> to continue (this also closes the ISO drive) ... Done. [prompt]> [prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" ./code00.py perm Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr 5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] 064bit on win32 Press <Enter> to continue ... Done.
In each of the 2 runs above, the effect is visible in Explorer (according to explanations from the beginning):