[misc] reinstate delay-loading of wininet and virtdisk DLLs

* Per #2272 and #1877, MinGW has issues when delay loading libraries, but
  it is possible to apply a workaround to alleviate them, by redefining
  DECLSPEC_IMPORT before including the corresponding headers.
* This is a bit more tricky to accomplish for virtdisk, as MinGW's windows.h
  header does include virtdisk.h on its own (rather than expect a formal
  include as MSVC does), so we have to prevent the virtdisk.h inclusion
  first, by defining a macro, and then apply our workaround.
* Per ea87573f-65ea-44a2-b4bb-ca96c0a136ab%40akeo.ie/#msg58793876
  we are hoping that this should be a temporary workaround and that the root
  cause of the issue will be fixed in binutils.
* Closes #2513.
This commit is contained in:
Mohmed abdel-fattah 2024-07-13 17:43:40 +01:00 committed by Pete Batard
parent 10d33c6658
commit 9b3c11122b
No known key found for this signature in database
GPG key ID: 38E0CF5E69EDD671
12 changed files with 117 additions and 159 deletions

View file

@ -17,7 +17,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// MinGW includes virdisk.h in windows.h, but we we don't want that
// because we must apply a delay-loading workaround, and that workaround
// has to apply between the winnt.h include and the virdisk.h include.
// So we define _INC_VIRTDISK, to prevent the virdisk.h include in
// windows.h, and then take care of the workaround (and virtdisk.h
// include) in vhd.h.
#define _INC_VIRTDISK
#include <windows.h>
#undef _INC_VIRTDISK
#include <windowsx.h>
#include <stdlib.h>
#include <io.h>
@ -68,9 +76,10 @@ static uint8_t wim_flags = 0;
static uint32_t progress_report_mask;
static uint64_t progress_offset = 0, progress_total = 100;
static wchar_t wmount_path[MAX_PATH] = { 0 }, wmount_track[MAX_PATH] = { 0 };
static char sevenzip_path[MAX_PATH];
static BOOL count_files;
static char sevenzip_path[MAX_PATH], physical_path[128] = "";
static int progress_op = OP_FILE_COPY, progress_msg = MSG_267;
static BOOL count_files;
static HANDLE mounted_handle = INVALID_HANDLE_VALUE;
static BOOL Get7ZipPath(void)
{
@ -897,23 +906,6 @@ BOOL WimApplyImage(const char* image, int index, const char* dst)
return dw;
}
// VirtDisk API Prototypes since we can't use delay-loading because of MinGW
// See https://github.com/pbatard/rufus/issues/2272#issuecomment-1615976013
PF_TYPE_DECL(WINAPI, DWORD, CreateVirtualDisk, (PVIRTUAL_STORAGE_TYPE, PCWSTR,
VIRTUAL_DISK_ACCESS_MASK, PSECURITY_DESCRIPTOR, CREATE_VIRTUAL_DISK_FLAG, ULONG,
PCREATE_VIRTUAL_DISK_PARAMETERS, LPOVERLAPPED, PHANDLE));
PF_TYPE_DECL(WINAPI, DWORD, OpenVirtualDisk, (PVIRTUAL_STORAGE_TYPE, PCWSTR,
VIRTUAL_DISK_ACCESS_MASK, OPEN_VIRTUAL_DISK_FLAG, POPEN_VIRTUAL_DISK_PARAMETERS, PHANDLE));
PF_TYPE_DECL(WINAPI, DWORD, AttachVirtualDisk, (HANDLE, PSECURITY_DESCRIPTOR,
ATTACH_VIRTUAL_DISK_FLAG, ULONG, PATTACH_VIRTUAL_DISK_PARAMETERS, LPOVERLAPPED));
PF_TYPE_DECL(WINAPI, DWORD, DetachVirtualDisk, (HANDLE, DETACH_VIRTUAL_DISK_FLAG, ULONG));
PF_TYPE_DECL(WINAPI, DWORD, GetVirtualDiskPhysicalPath, (HANDLE, PULONG, PWSTR));
PF_TYPE_DECL(WINAPI, DWORD, GetVirtualDiskOperationProgress, (HANDLE, LPOVERLAPPED, PVIRTUAL_DISK_PROGRESS));
PF_TYPE_DECL(WINAPI, DWORD, GetVirtualDiskInformation, (HANDLE, PULONG, PGET_VIRTUAL_DISK_INFO, PULONG));
static char physical_path[128] = "";
static HANDLE mounted_handle = INVALID_HANDLE_VALUE;
// Mount an ISO or a VHD/VHDX image and provide its size
// Returns the physical path of the mounted image or NULL on error.
char* VhdMountImageAndGetSize(const char* path, uint64_t* disk_size)
@ -927,12 +919,6 @@ char* VhdMountImageAndGetSize(const char* path, uint64_t* disk_size)
wconvert(path);
char *ret = NULL, *ext = NULL;
PF_INIT_OR_OUT(OpenVirtualDisk, VirtDisk);
PF_INIT_OR_OUT(AttachVirtualDisk, VirtDisk);
PF_INIT_OR_OUT(GetVirtualDiskPhysicalPath, VirtDisk);
if (disk_size != NULL)
PF_INIT_OR_OUT(GetVirtualDiskInformation, VirtDisk);
if (wpath == NULL)
return NULL;
@ -946,7 +932,7 @@ char* VhdMountImageAndGetSize(const char* path, uint64_t* disk_size)
else if (safe_stricmp(ext, ".vhd") == 0)
vtype.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_VHD;
r = pfOpenVirtualDisk(&vtype, wpath, VIRTUAL_DISK_ACCESS_READ | VIRTUAL_DISK_ACCESS_GET_INFO,
r = OpenVirtualDisk(&vtype, wpath, VIRTUAL_DISK_ACCESS_READ | VIRTUAL_DISK_ACCESS_GET_INFO,
OPEN_VIRTUAL_DISK_FLAG_NONE, NULL, &mounted_handle);
if (r != ERROR_SUCCESS) {
SetLastError(r);
@ -955,7 +941,7 @@ char* VhdMountImageAndGetSize(const char* path, uint64_t* disk_size)
}
vparams.Version = ATTACH_VIRTUAL_DISK_VERSION_1;
r = pfAttachVirtualDisk(mounted_handle, NULL, ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY |
r = AttachVirtualDisk(mounted_handle, NULL, ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY |
ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER, 0, &vparams, NULL);
if (r != ERROR_SUCCESS) {
SetLastError(r);
@ -963,7 +949,7 @@ char* VhdMountImageAndGetSize(const char* path, uint64_t* disk_size)
goto out;
}
r = pfGetVirtualDiskPhysicalPath(mounted_handle, &size, wtmp);
r = GetVirtualDiskPhysicalPath(mounted_handle, &size, wtmp);
if (r != ERROR_SUCCESS) {
SetLastError(r);
uprintf("Could not obtain physical path for mounted image '%s': %s", path, WindowsErrorString());
@ -975,7 +961,7 @@ char* VhdMountImageAndGetSize(const char* path, uint64_t* disk_size)
*disk_size = 0;
disk_info.Version = GET_VIRTUAL_DISK_INFO_SIZE;
size = sizeof(disk_info);
r = pfGetVirtualDiskInformation(mounted_handle, &size, &disk_info, NULL);
r = GetVirtualDiskInformation(mounted_handle, &size, &disk_info, NULL);
if (r != ERROR_SUCCESS) {
SetLastError(r);
uprintf("Could not obtain virtual size of mounted image '%s': %s", path, WindowsErrorString());
@ -995,12 +981,10 @@ out:
void VhdUnmountImage(void)
{
PF_INIT_OR_OUT(DetachVirtualDisk, VirtDisk);
if ((mounted_handle == NULL) || (mounted_handle == INVALID_HANDLE_VALUE))
goto out;
pfDetachVirtualDisk(mounted_handle, DETACH_VIRTUAL_DISK_FLAG_NONE, 0);
DetachVirtualDisk(mounted_handle, DETACH_VIRTUAL_DISK_FLAG_NONE, 0);
safe_closehandle(mounted_handle);
out:
physical_path[0] = 0;
@ -1022,9 +1006,6 @@ static DWORD WINAPI VhdSaveImageThread(void* param)
OVERLAPPED overlapped = { 0 };
DWORD r = ERROR_NOT_FOUND, flags;
PF_INIT_OR_OUT(CreateVirtualDisk, VirtDisk);
PF_INIT_OR_OUT(GetVirtualDiskOperationProgress, VirtDisk);
assert(img_save->Type == VIRTUAL_STORAGE_TYPE_DEVICE_VHD ||
img_save->Type == VIRTUAL_STORAGE_TYPE_DEVICE_VHDX);
@ -1052,7 +1033,7 @@ static DWORD WINAPI VhdSaveImageThread(void* param)
// CreateVirtualDisk() does not have an overwrite flag...
DeleteFileW(wDst);
r = pfCreateVirtualDisk(&vtype, wDst, VIRTUAL_DISK_ACCESS_NONE, NULL,
r = CreateVirtualDisk(&vtype, wDst, VIRTUAL_DISK_ACCESS_NONE, NULL,
flags, 0, (PCREATE_VIRTUAL_DISK_PARAMETERS)&vparams, &overlapped, &handle);
if (r != ERROR_SUCCESS && r != ERROR_IO_PENDING) {
SetLastError(r);
@ -1066,7 +1047,7 @@ static DWORD WINAPI VhdSaveImageThread(void* param)
CancelIoEx(handle, &overlapped);
goto out;
}
if (pfGetVirtualDiskOperationProgress(handle, &overlapped, &vprogress) == ERROR_SUCCESS) {
if (GetVirtualDiskOperationProgress(handle, &overlapped, &vprogress) == ERROR_SUCCESS) {
if (vprogress.OperationStatus == ERROR_IO_PENDING)
UpdateProgressWithInfo(OP_FORMAT, MSG_261, vprogress.CurrentValue, vprogress.CompletionValue);
}