QT案例 Qt调用WIMGAPI库,读取/修改/装载WIM、ESD格式的镜像文件

WIMGAPI库是 Windows 操作系统中的一个应用程序编程接口(API)可用于创建,编辑,提取浏览和部署 WIM、ESD格式的镜像文件。
这里只简单演示在Qt Creator, Mscv2017 Debug,WINDOWS 开发环境下的调用完整实例。

目录

    • WIMGAPI描述
      • 数据预处理
      • 获取镜像的相关信息
      • 导出指定系统中的文件
      • 获取镜像目录结构(装载/卸载镜像)
      • 提取镜像到指定目录

WIMGAPI描述

WIMGAPI (Windows Imaging API)是 Windows 操作系统中的一个应用程序编程接口(API),用于处理 Windows 映像(.wim)文件格式。Windows 映像是一种压缩的文件容器,可用于存储操作系统、应用程序和驱动程序等文件
注:https://www.cnblogs.com/suv789/p/17549323.html
WIMGAPI是适合WINDOWS 环境下处理WIM、ESD镜像格式的库,
常用方法说明:

  • WIMCreateFile 创建新的图像文件或打开现有的图像文件。
  • WIMApplyImage 将图像应用于Windows图像的目录路径(。wim)文件。
  • WIMCaptureImage 从目录路径捕获图像,并将其存储在图像文件中。
  • WIMCloseHandle 关闭打开的Windows imaging(。wim)文件或图像句柄。
  • WIMCommitImageHandle 将已装载映像中的更改保存回. wim文件。
  • WIMCopyFile 将现有文件复制到新文件中。通过回调函数通知应用程序它的进度。如果源文件包含验证数据,则在复制操作期间会验证文件的内容。
  • WIMDeleteImage 从. wim (Windows映像)文件中删除映像,使其无法被访问。但是,文件资源仍然可供WIMSetReferenceFile功能。
  • WIMDeleteImageMounts 从以前装载映像的所有目录中删除映像。
  • WIMExportImage 从一个Windows映像(.wim)文件复制到另一个文件。
  • WIMExtractImagePath 从Windows映像(.wim)文件复制到指定位置。
  • WIMGetAttributes 返回存储在映像文件中的卷映像的数量。
  • WIMGetImageCount 返回存储在Windows映像中的卷映像的数量。wim)文件。
  • WIMGetImageInformation 返回有关中图像的信息。wim (Windows映像)文件。
  • WIMGetMessageCallbackCount 返回图像库当前注册的回调例程的计数。
  • WIMGetMountedImageHandle 返回一个WIM句柄和一个镜像句柄,对应于一个挂载的镜像目录。
  • WIMGetMountedImageInfo 返回当前装载的映像列表。
  • WIMGetMountedImageInfoFromHandle 查询已装载图像句柄的状态。
  • WIMGetMountedImages 返回当前装载的映像列表。此功能已被取代WIMGetMountedImageInfo.
  • WIMLoadImage 从Windows映像加载卷映像(。wim)文件。
  • WIMMessageCallback 与一起使用的应用程序定义的函数WIMRegisterMessageCallback或者WIMUnregisterMessageCallback功能。
  • WIMMountImage 将映像装入Windows映像(。wim)文件复制到指定目录。
  • WIMMountImageHandle 将映像装入Windows映像(。wim)文件复制到指定目录。
  • WIMRegisterLogFile 将用于调试或跟踪目的的日志文件注册到当前WIMGAPI会话中。
  • WIMRegisterMessageCallback 用特定于图像的数据注册要调用的函数。有关可以处理的消息的信息,请参见信息.
  • WIMRemountImage 重新激活以前装载到指定目录的已装载映像。
  • WIMSetBootImage 将具有给定映像索引的映像标记为可启动。
  • WIMSetImageInformation 将有关图像的信息存储在Windows图像(。wim)文件。
  • WIMSetReferenceFile 启用WIMApplyImage和WIMCaptureImage使用替代的函数。文件资源的wim文件。当使用相似数据捕获多个图像时,这可以优化存储。
  • WIMSetTemporaryPath 设置临时图像文件的存储位置。
  • WIMSplitFile 启用大的Windows映像(。wim)文件分割成较小的部分,以便在较小形式的介质上复制或存储。
  • WIMUnmountImage 卸载Windows映像中已装载的映像(。wim)文件从指定的目录。
  • WIMUnmountImageHandle 从Windows映像中卸载映像(。wim ),它以前与一起安装WIMMountImageHandle功能。
  • WIMUnregisterLogFile 出于调试或跟踪目的,从当前WIMGAPI会话中注销日志文件。
  • WIMUnregisterMessageCallback 注销用特定于图像的数据调用的函数。

具体参数建议查看WIMGAPI 中的API说明
或者通过GItHub中获取wingapi的一些宏定义和类结构
https://github.com/VulpesSARL/MiniNT5-Tools/blob/b3bbc6c2c1af7207438a34b1546fa67ab7a038e2/FoxCWrapperWIM/wimgapi.h

数据预处理

WIMGAPI 是通过LoadLibraryExW 加载Wimgapi库获取各种Api的调用。
这里只包含部分使用到的api和宏定义,
完整的APi和宏定义建议查看GItHub上面的wimgapi.h文件内容

#define PF_INIT(proc, name)					if (pf##proc == NULL) pf##proc = \(proc##_t) GetProcAddress(GetLibraryHandle(#name), #proc)
#define PF_INIT_OR_OUT(proc, name)			do {PF_INIT(proc, name);         \if (pf##proc == NULL) {qDebug("Unable to locate %s() in '%s.dll': %s",  \
#proc, #name, GetLastError()); goto out;} } while(0)// From https://docs.microsoft.com/en-us/previous-versions/msdn10/dd834960(v=msdn.10)
// as well as https://msfn.org/board/topic/150700-wimgapi-wimmountimage-progressbar/
enum WIMMessage {WIM_MSG = WM_APP + 0x1476,WIM_MSG_TEXT,WIM_MSG_PROGRESS,	// Indicates an update in the progress of an image application.WIM_MSG_PROCESS,	// Enables the caller to prevent a file or a directory from being captured or applied.WIM_MSG_SCANNING,	// Indicates that volume information is being gathered during an image capture.WIM_MSG_SETRANGE,	// Indicates the number of files that will be captured or applied.WIM_MSG_SETPOS,		// Indicates the number of files that have been captured or applied.WIM_MSG_STEPIT,		// Indicates that a file has been either captured or applied.WIM_MSG_COMPRESS,	// Enables the caller to prevent a file resource from being compressed during a capture.WIM_MSG_ERROR,		// Alerts the caller that an error has occurred while capturing or applying an image.WIM_MSG_ALIGNMENT,	// Enables the caller to align a file resource on a particular alignment boundary.WIM_MSG_RETRY,		// Sent when the file is being reapplied because of a network timeout.WIM_MSG_SPLIT,		// Enables the caller to align a file resource on a particular alignment boundary.WIM_MSG_FILEINFO,	// Used in conjunction with WimApplyImages()'s WIM_FLAG_FILEINFO flag to provide detailed file info.WIM_MSG_INFO,		// Sent when an info message is available.WIM_MSG_WARNING,	// Sent when a warning message is available.WIM_MSG_CHK_PROCESS,WIM_MSG_SUCCESS = 0,WIM_MSG_ABORT_IMAGE = -1
};/* Action type, for progress bar breakdown */
enum action_type {OP_NOOP_WITH_TASKBAR = -3,OP_NOOP = -2,OP_INIT = -1,OP_ANALYZE_MBR = 0,OP_BADBLOCKS,OP_ZERO_MBR,OP_PARTITION,OP_FORMAT,OP_CREATE_FS,OP_FIX_MBR,OP_FILE_COPY,OP_PATCH,OP_FINALIZE,OP_MAX
};enum
{WIM_COMPRESS_NONE = 0,WIM_COMPRESS_XPRESS = 1,WIM_COMPRESS_LZX = 2
};#define WIM_GENERIC_READ					GENERIC_READ
#define WIM_GENERIC_WRITE                   GENERIC_WRITE
#define WIM_GENERIC_MOUNT                   GENERIC_EXECUTE
#define WIM_OPEN_EXISTING					OPEN_EXISTING
#define WIM_OPEN_ALWAYS                     OPEN_ALWAYS
#define WIM_UNDOCUMENTED_BULLSHIT			0x20000000#define WIM_FLAG_RESERVED					0x00000001
#define WIM_FLAG_VERIFY						0x00000002
#define WIM_FLAG_INDEX						0x00000004
#define WIM_FLAG_NO_APPLY					0x00000008
#define WIM_FLAG_NO_DIRACL					0x00000010
#define WIM_FLAG_NO_FILEACL					0x00000020
#define WIM_FLAG_SHARE_WRITE				0x00000040
#define WIM_FLAG_FILEINFO					0x00000080
#define WIM_FLAG_NO_RP_FIX					0x00000100
#define WIM_FLAG_MOUNT_READONLY            0x00000200
#define INVALID_CALLBACK_VALUE				0xFFFFFFFFstatic HMODULE GetLibraryHandle(const char* szLibraryName)
{HMODULE h = NULL;const wchar_t* wszLibraryName = NULL;int size;if (szLibraryName == NULL || szLibraryName[0] == 0)goto out;size = MultiByteToWideChar(CP_UTF8, 0, szLibraryName, -1, NULL, 0);if ((size <= 1) || ((wszLibraryName = (wchar_t*)calloc(size, sizeof(wchar_t))) == NULL) ||(MultiByteToWideChar(CP_UTF8, 0, szLibraryName, -1, (LPWSTR)wszLibraryName, size) != size))goto out;// If the library is already opened, just return a handle (that doesn't need to be freed)if ((h = GetModuleHandleW(wszLibraryName)) != NULL)goto out;h = LoadLibraryExW(wszLibraryName, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);if(h==NULL)qDebug("Unable to load '%S.dll': %s", wszLibraryName, GetLastError());
out:free((LPWSTR)wszLibraryName);return h;
}

静态实例:

typedef HANDLE (WINAPI *WIMCreateFile_t)(PWSTR, DWORD, DWORD, DWORD, DWORD, PDWORD);
static WIMCreateFile_t pfWIMCreateFile=NULL;typedef BOOL (WINAPI *WIMGetImageInformation_t)(HANDLE, PVOID , PDWORD);
static WIMGetImageInformation_t pfWIMGetImageInformation=NULL;typedef BOOL (WINAPI *WIMSetTemporaryPath_t)( HANDLE ,PWSTR );
static WIMSetTemporaryPath_t pfWIMSetTemporaryPath=NULL;typedef DWORD (WINAPI *WIMGetImageCount_t)( HANDLE );
static WIMGetImageCount_t pfWIMGetImageCount=NULL;typedef HANDLE (WINAPI *WIMLoadImage_t)(HANDLE ,DWORD );
static WIMLoadImage_t pfWIMLoadImage=NULL;typedef BOOL (WINAPI *WIMCloseHandle_t)(HANDLE);
static WIMCloseHandle_t pfWIMCloseHandle=NULL;typedef BOOL (WINAPI *WIMApplyImage_t)(HANDLE, PCWSTR, DWORD);
static WIMApplyImage_t pfWIMApplyImage=NULL;typedef BOOL (WINAPI *WIMSetBootImage_t)(HANDLE, DWORD);
static WIMSetBootImage_t pfWIMSetBootImage=NULL;typedef BOOL (WINAPI *WIMMountImage_t)(PCWSTR, PCWSTR, DWORD, PCWSTR);
static WIMMountImage_t pfWIMMountImage=NULL;typedef BOOL (WINAPI *WIMUnmountImage_t)(PCWSTR, PCWSTR, DWORD, BOOL);
static WIMUnmountImage_t pfWIMUnmountImage=NULL;typedef DWORD (WINAPI *WIMRegisterMessageCallback_t)(HANDLE, FARPROC, PVOID);
static WIMRegisterMessageCallback_t pfWIMRegisterMessageCallback=NULL;typedef DWORD (WINAPI *WIMUnregisterMessageCallback_t)(HANDLE, FARPROC);
static WIMUnregisterMessageCallback_t pfWIMUnregisterMessageCallback=NULL;typedef HANDLE (WINAPI *WIMCaptureImage_t)(HANDLE , PCWSTR , DWORD);
static WIMCaptureImage_t pfWIMCaptureImage=NULL;typedef BOOL (WINAPI *WIMMountImageHandle_t)(HANDLE, PCWSTR, DWORD);
static WIMMountImageHandle_t pfWIMMountImageHandle=NULL;typedef BOOL (WINAPI *WIMUnmountImageHandle_t)(HANDLE, DWORD);
static WIMUnmountImageHandle_t pfWIMUnmountImageHandle=NULL;typedef BOOL (WINAPI *WIMExtractImagePath_t) (HANDLE, PWSTR, PWSTR, DWORD);
static WIMExtractImagePath_t pfWIMExtractImagePath=NULL;

格式转换:
在涉及到windows api的接口调用时,
Qt开发环境下,这两个方法是绝对少不了的,毕竟传入路径的时候,都需要转换文本格式。

/** Converts an UTF8 string to UTF-16 (allocate returned string)* Returns NULL on error*/
static wchar_t* _utf8_to_wchar(const char* str)
{//    qDebug()<<"[_utf8_to_wchar] -->";int size = 0;wchar_t* wstr = NULL;if (str == NULL)return NULL;// Convert the empty string tooif (str[0] == 0)return (wchar_t*)calloc(1, sizeof(wchar_t));// Find out the size we need to allocate for our converted stringsize = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);if (size <= 1)	// An empty string would be size 1return NULL;if ((wstr = (wchar_t*)calloc(size, sizeof(wchar_t))) == NULL)return NULL;if (utf8_to_wchar_no_alloc(str, wstr, size) != size) {sfree(wstr);return NULL;}return wstr;
}/** Converts an UTF-16 string to UTF8 (allocate returned string)* Returns NULL on error*/
static char* _wchar_to_utf8(const wchar_t* wstr)
{int size = 0;char* str = NULL;/* Find out the size we need to allocate for our converted string */size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);if (size <= 1) /* An empty string would be size 1 */return NULL;if ((str = (char*)calloc(size, 1)) == NULL)return NULL;if (wchar_to_utf8_no_alloc(wstr, str, size) != size) {free(str);return NULL;}return str;
}

获取镜像的相关信息

WIM、ESD镜像版本信息实际上就是一个XML格式保存的,
通过WIMGetImageInformation 获取
示例中整个操作是将XML写入了一个临时文件,
值得注意的是pfWIMCreateFile 打开WIM时需要将dwFlagsAndAttributes设置为WIM_UNDOCUMENTED_BULLSHIT
如果设置为0,测试部分镜像会无法加载;

 	TempFilePath tempObj; //一个用于生成临时文件的类//临时文件夹wchar_t* wtemp=tempObj.GetTempDirU();wchar_t* wimage;///临时文件wchar_t* wdst=tempObj.GetTempFileNameU(1);///XML格式信息wchar_t* wim_XMLinfo;HANDLE hWim = NULL;HANDLE hFile = NULL;DWORD dw = 0;DWORD dwFlagsAndAttributes=WIM_UNDOCUMENTED_BULLSHIT;//Image_path 镜像文件路径///使用wimgapi库读取数据wimage=_utf8_to_wchar(Image_path.toStdString().c_str());//实例化API PF_INIT_OR_OUT(WIMCreateFile, Wimgapi);PF_INIT_OR_OUT(WIMSetTemporaryPath, Wimgapi);PF_INIT_OR_OUT(WIMCloseHandle, Wimgapi);PF_INIT_OR_OUT(WIMGetImageInformation, Wimgapi);PF_INIT_OR_OUT(WIMGetImageCount, Wimgapi);hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ, WIM_OPEN_EXISTING,dwFlagsAndAttributes , 0, NULL);if (hWim == NULL) {qDebug("  Could not access image: %d", GetLastError());goto out;}///设置临时文件夹路径if (!pfWIMSetTemporaryPath(hWim, wtemp)) {qDebug("  Could not set temp path: %d", GetLastError());goto out;}///获取镜像包含的系统数量int Image_Count=pfWIMGetImageCount(hWim);if(Image_Count==0)qDebug("  Could not get image count: %d", GetLastError());qDebug()<<"[Image_Count] "<<Image_Count;///获取 系统的xml信息if (!pfWIMGetImageInformation(hWim, &wim_XMLinfo, &dw) || (dw == 0)) {qDebug("  Could not access WIM info: %d", GetLastError());goto out;}///写入临时文件hFile = CreateFileW(wdst, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if ((hFile == INVALID_HANDLE_VALUE)|| (!WriteFile(hFile, wim_XMLinfo, dw, &dw, NULL))) {qDebug("  Could not extract file: %s", GetLastError());goto out;}CloseHandle(hFile);hFile=INVALID_HANDLE_VALUE;///打开xml读取数据//Parser_XML(QString::fromWCharArray(wdst));
out:if ( (hWim != NULL)) {qDebug("Closing: %s", Image_path.toStdString().c_str());if (hWim != NULL)pfWIMCloseHandle(hWim);}if(hFile != INVALID_HANDLE_VALUE)CloseHandle(hFile);safe_free(wtemp);safe_free(wimage);safe_free(wdst);

导出指定系统中的文件

一个WIM、ESD镜像文件中至少包含一个系统镜像,
pfWIMLoadImage加载镜像时都需要先设置一个临时文件夹;
默认镜像索引从1开始,小于等于镜像系统数量;

void Lib_Wimgapi::Export_File_by(int index,QString wimpath,QString outfile)
{TempFilePath tempObj;//临时文件夹wchar_t* wtemp=tempObj.GetTempDirU();///镜像路径wchar_t* wimage=_utf8_to_wchar(Image_path.toStdString().c_str());///WIM 镜像路径 如 windows\\boot.exewchar_t* wsrc=_utf8_to_wchar(wimpath.toStdString().c_str());///输出路径 如 C:\\Users\\admin\\Desktop\\boot.exewchar_t* wdst=_utf8_to_wchar(outfile.toStdString().c_str());HANDLE hWim = NULL;HANDLE hImage=NULL;DWORD dw=0;///实例化函数方法PF_INIT_OR_OUT(WIMCreateFile, Wimgapi);PF_INIT_OR_OUT(WIMSetTemporaryPath, Wimgapi);PF_INIT_OR_OUT(WIMCloseHandle, Wimgapi);PF_INIT_OR_OUT(WIMLoadImage, Wimgapi);PF_INIT_OR_OUT(WIMExtractImagePath, Wimgapi);hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ, WIM_OPEN_EXISTING,WIM_UNDOCUMENTED_BULLSHIT , 0, NULL);if (hWim == NULL) {qDebug("  Could not access image: %d", GetLastError());goto out;}///设置临时文件夹路径if (!pfWIMSetTemporaryPath(hWim, wtemp)) {qDebug("  Could not set temp path: %d", GetLastError());goto out;}///至少为1int WIM_INDEX=qMin(qMax(1,index),Image_Count);hImage = pfWIMLoadImage(hWim, WIM_INDEX);if (hImage == NULL) {qDebug("  Could not set index: %d", GetLastError());goto out;}///输出文件if (!pfWIMExtractImagePath(hImage, wsrc, wdst, dw)) {qDebug("  Could not extract file: %d", GetLastError());goto out;}out:if (hWim != NULL || hWim != hImage) {qDebug("Closing: %s", Image_path.toStdString().c_str());if (hWim != NULL)pfWIMCloseHandle(hWim);if (hImage != NULL)pfWIMCloseHandle(hImage);}safe_free(wtemp);safe_free(wimage);safe_free(wsrc);safe_free(wdst);
}

获取镜像目录结构(装载/卸载镜像)

WIMGAPI库中貌似没有可以直接获取目录结构的函数,写示例的时候我是先通过
加载镜像(pfWIMLoadImage)->
装载镜像(WIMMountImageHandle)->
读取目录结构(文件夹遍历)->
卸载镜像(WIMUnmountImageHandle)
这个流程来获取目录结构的;

 	TempFilePath tempObj;HANDLE hWim = NULL;HANDLE hImage = NULL;///Image_pathwchar_t* wimage = _utf8_to_wchar(Image_path.toStdString().c_str());//临时文件夹wchar_t* wtemp=tempObj.GetTempDirU();//用于装载的路径QDir tempMountDir(QString::fromWCharArray(wtemp)+"\\TempMount_WIMGAPI");if(!tempMountDir.exists())tempMountDir.mkpath(QString::fromWCharArray(wtemp)+"\\TempMount_WIMGAPI");wchar_t* wdst=_utf8_to_wchar(QString(QString::fromWCharArray(wtemp)+"\\TempMount_WIMGAPI").toStdString().c_str());QString TempFile=QString::fromWCharArray(wdst);qDebug()<<"临时装载路径: "<<TempFile;//PF_INIT_OR_OUT(WIMRegisterMessageCallback, Wimgapi);PF_INIT_OR_OUT(WIMCreateFile, Wimgapi);PF_INIT_OR_OUT(WIMSetTemporaryPath, Wimgapi);PF_INIT_OR_OUT(WIMLoadImage, Wimgapi);PF_INIT_OR_OUT(WIMApplyImage, Wimgapi);PF_INIT_OR_OUT(WIMCloseHandle, Wimgapi);//PF_INIT_OR_OUT(WIMUnregisterMessageCallback, Wimgapi);PF_INIT_OR_OUT(WIMMountImageHandle, Wimgapi);PF_INIT_OR_OUT(WIMUnmountImageHandle, Wimgapi);// 调试信息
//    if (pfWIMRegisterMessageCallback(NULL, (FARPROC)WimProgressCallback, NULL) == INVALID_CALLBACK_VALUE) {
//        qDebug("  Could not set progress callback: %d", GetLastError());
//        goto out;
//    }hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ|WIM_GENERIC_MOUNT, WIM_OPEN_EXISTING,WIM_UNDOCUMENTED_BULLSHIT , 0, NULL);if (hWim == NULL) {qDebug("  Could not access image: %d", GetLastError());goto out;}if (!pfWIMSetTemporaryPath(hWim, wtemp)) {qDebug("  Could not set temp path: %d", GetLastError());goto out;}int WIM_INDEX=qMax(1,index.toInt());hImage = pfWIMLoadImage(hWim, WIM_INDEX);if (hImage == NULL) {qDebug("  Could not set index: %d", GetLastError());goto out;}///清除历史缓存//! 方案一 用这种方法可以检查文件目录 但是无法获取文件的属性
//    Fetch_Files.clear();
//    // Run a first pass using WIM_FLAG_NO_APPLY to count the files
//    if (!pfWIMApplyImage(hImage, wdst, WIM_FLAG_NO_APPLY)) {
//        qDebug("  Could not count the files to apply: %d", GetLastError());
//        goto out;
//    }//! 方案二 通过装载卸载的方式 获取文件目录结构if(!pfWIMMountImageHandle(hImage,wdst,WIM_FLAG_MOUNT_READONLY)){qDebug("Could not Mount Image: %d", GetLastError());goto out;}//遍历目录结构//Lib_Deploy_Environment::getInstance().EnumerateFiles(TempFile,Fetch_Files);//! 如果需要对镜像镜像修改 可以在此处操作文件目录/文件 然后提交保存//!WIMCommitImageHandle 保存装载后的更改!if(!pfWIMUnmountImageHandle(hImage,0)){//dism /Get-MountedWimInfo//dism /Cleanup-Wim//CMD_WRITE("dism /Cleanup-Wim");qDebug("Could not Unmount Image: %d", GetLastError());}
out:if ((hImage != NULL) || (hWim != NULL)) {qDebug("Closing: %s", Image_path.toStdString().c_str());if (hImage != NULL)pfWIMCloseHandle(hImage);if (hWim != NULL)pfWIMCloseHandle(hWim);}
//    if (pfWIMUnregisterMessageCallback != NULL)
//        pfWIMUnregisterMessageCallback(NULL, (FARPROC)WimProgressCallback);safe_free(wimage);safe_free(wdst);safe_free(wtemp);

其中需要注意的是:
如果因为各种原因卸载或者装载失败,都需要调用Windwos系统自带的Dism.exe删除不完整的记录
CMD执行 dism.exe /Cleanup-Wim

提取镜像到指定目录

通过pfWIMApplyImage 提取镜像时,可以加上WIMRegisterMessageCallback的回调函数,获取提取文件进度,也可以实现简单的进度条效果,

//!回调函数
static DWORD WimProgressCallback(DWORD dwMsgId, WPARAM wParam, LPARAM lParam, PVOID pvIgnored)
{//qDebug()<<"[dwMsgId] "<<dwMsgId;PBOOL pbCancel = NULL;PWIN32_FIND_DATA pFileData;const char* level = NULL;uint64_t size;switch (dwMsgId) {case WIM_MSG_PROGRESS:qDebug()<<"[WIM_MSG_PROGRESS] -->";// The default WIM progress is useless for apply (freezes at 95%, which is usually when// only half the files have been processed), so we only use it for mounting/unmounting.//UpdateProgressWithInfo(progress_op, progress_msg, progress_offset + wParam, progress_total);break;case WIM_MSG_PROCESS:{qDebug()<<"[WIM_MSG_PROCESS] -->";PWSTR pszFullPath=(PWSTR)wParam ;qDebug()<<"WIM_MSG_PROCESS pszFullPath : "<<QString::fromWCharArray(pszFullPath);// The amount of files processed is overwhelming (16k+ for a typical image),// and trying to display it *WILL* slow us down, so we don't.pbCancel = (PBOOL)lParam;*pbCancel = TRUE;break;}
//            break;case WIM_MSG_FILEINFO:{qDebug()<<"[WIM_MSG_FILEINFO] -->";pFileData = (PWIN32_FIND_DATA)lParam;if (pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {//!文件夹qDebug()<<"[Dir] "<<QString::fromWCharArray((PWSTR)pFileData->cFileName);qDebug()<<"[wParam] "<<QString::fromWCharArray((PWSTR)wParam);} else {//!文件qDebug()<<"[File] "<<QString::fromWCharArray(pFileData->cFileName);qDebug()<<"[wParam] "<<QString::fromWCharArray((PWSTR)wParam);}break;}case WIM_MSG_RETRY:qDebug()<<"[WIM_MSG_RETRY] -->";level = "retry";// fall throughcase WIM_MSG_INFO:if (level == NULL) level = "info";// fall throughcase WIM_MSG_WARNING:if (level == NULL) level = "warning";// fall throughcase WIM_MSG_ERROR:if (level == NULL) level = "error";SetLastError((DWORD)lParam);qDebug("WIM processing %s: %S [%d]\n", level, (PWSTR)wParam, GetLastError());break;}return WIM_MSG_SUCCESS;
}
	//!提取镜像TempFilePath tempObj;//临时文件夹wchar_t* wtemp=tempObj.GetTempDirU();//QString  Imagepath 镜像路径wchar_t* wimage=_utf8_to_wchar(Imagepath.toStdString().c_str());//QString descpath 提取到指定文件夹wchar_t* wdst=_utf8_to_wchar(descpath.toStdString().c_str());HANDLE hWim = NULL;HANDLE hImage=NULL;DWORD dw=0;PF_INIT_OR_OUT(WIMRegisterMessageCallback, Wimgapi);PF_INIT_OR_OUT(WIMCreateFile, Wimgapi);PF_INIT_OR_OUT(WIMSetTemporaryPath, Wimgapi);PF_INIT_OR_OUT(WIMLoadImage, Wimgapi);PF_INIT_OR_OUT(WIMApplyImage, Wimgapi);PF_INIT_OR_OUT(WIMCloseHandle, Wimgapi);PF_INIT_OR_OUT(WIMUnregisterMessageCallback, Wimgapi);//设置回调函数if (pfWIMRegisterMessageCallback(NULL, (FARPROC)WimProgressCallback, NULL) == INVALID_CALLBACK_VALUE) {qDebug("  Could not set progress callback: %d", GetLastError());goto out;}hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ|WIM_GENERIC_MOUNT, WIM_OPEN_EXISTING,WIM_UNDOCUMENTED_BULLSHIT , 0, NULL);if (hWim == NULL) {qDebug("  Could not access image: %d", GetLastError());goto out;}if (!pfWIMSetTemporaryPath(hWim, wtemp)) {qDebug("  Could not set temp path: %d", GetLastError());goto out;}//指定镜像索引indexhImage = pfWIMLoadImage(hWim, index);if (hImage == NULL) {qDebug("  Could not set index: %d", GetLastError());goto out;}//! WIM_FLAG_FILEINFO 提取镜像if (!pfWIMApplyImage(hImage, wdst, WIM_FLAG_FILEINFO)) {qDebug("  Could not Export WIM Image: %d", GetLastError());goto out;}out:if ((hImage != NULL) || (hWim != NULL)) {qDebug("Closing: %s", Image_path.toStdString().c_str());if (hImage != NULL)pfWIMCloseHandle(hImage);if (hWim != NULL)pfWIMCloseHandle(hWim);}if (pfWIMUnregisterMessageCallback != NULL)pfWIMUnregisterMessageCallback(NULL, (FARPROC)WimProgressCallback);safe_free(wimage);safe_free(wdst);safe_free(wtemp);

提示:
pfWIMApplyImage 函数的

  • WIM_FLAG_NO_APPLY 属性不提取文件,只会在回调函数中返回WIM_MSG_PROCESS信号,同时可输出文件路径,可用于统计文件目录数量
  • WIM_FLAG_FILEINFO 属性会提取文件,按目录结构写入指定文件夹中,会在回调函数中返回WIM_MSG_FILEINFO信号。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/651488.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构C++队列(数组模拟)

队列也是比较简单的数据结构了&#xff0c;队列的特点是先进先出 下面代码中hh是队头&#xff0c;tt是队尾。 默认是从队尾插入数据&#xff0c;队头弹出数据。 代码中的数据结构可以使用这图片来解释&#xff0c;整个区间是数组q。hh和tt分别控制队头和队尾。 例题&#x…

前端-打卡每日面试题-数据类型(2024.1.26)

一、分类 在JavaScript中&#xff0c;数据类型可以分为两大类&#xff1a;原始数据类型&#xff08;Primitive Types&#xff09;和引用数据类型&#xff08;Reference Types&#xff09;。 1. 原始数据类型&#xff08;Primitive Types&#xff09;: Number&#xff08;数字…

AI作画工具 stable-diffusion-webui 一键安装工具(A1111-Web-UI-Installer)

安装 下载最新版本确保你的 NVIDIA 显卡驱动程序是最新的&#xff08;起码不能太老&#xff09;启动安装程序在欢迎屏幕上单击下一步在屏幕上&#xff0c;选择要安装的内容如果你已经安装了 Python 3.10 和 Git&#xff0c;那么可以取消选中如果你不知道这些是什么&#xff0c…

C++(5) 构造函数、析构函数和封装案例

文章目录 构造函数、析构函数和封装案例1. 构造函数和析构函数1.1 概述1.2 案例1.3 编译器自行提供构造函数1.4 拷贝构造函数和特殊用法1.5 构造函数总结和要求 2. 封装案例2.1 封装的终极奥义2.2 封装一个 Cube 立方体 构造函数、析构函数和封装案例 1. 构造函数和析构函数 …

[01 LinuxShell ] 清华大学电子系科协软件部2023暑期培训

清华大学电子系科协软件部2023暑期培训_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV11N4y187ZE/?spm_id_from333.1007.top_right_bar_window_custom_collection.content.click&vd_source3ef6540f8473c7367625a53b7b77fd66 本视频为清华大学电子系科协软件部2023…

简单介绍----微服务和Spring Cloud

微服务和SpringCloud 1.什么是微服务&#xff1f; 微服务是将一个大型的、单一的应用程序拆分成多个小型服务&#xff0c;每个服务负责实现特定的业务功能&#xff0c;并且可以通过网络通信与其他服务通信。微服务的优点是开发更灵活&#xff08;不同的微服务可以使用不同的开…

nginx使用stream模块代理端口

今天原本准备将本地金仓的54321端口进行代理的&#xff0c;但是发现代理后总是无法访问。后来突然发现之前使用nginx代理的是一个地址而不是端口。因此做以下笔记用来做记录。 一、stream安装与配置 假设nginx在usr/local/nginx中 1. 测试当前nginx是否有stream模块 ./usr/…

FPGA 通过 UDP 以太网传输 JPEG 压缩图片

FPGA 通过 UDP 以太网传输 JPEG 压缩图片 简介 在 FPGA 上实现了 JPEG 压缩和 UDP 以太网传输。从摄像机的输入中获取单个灰度帧&#xff0c;使用 JPEG 标准对其进行压缩&#xff0c;然后通过UDP以太网将其传输到另一个设备&#xff08;例如计算机&#xff09;&#xff0c;所有…

代码随想录算法刷题训练营day17

代码随想录算法刷题训练营day17&#xff1a;LeetCode(110)平衡二叉树 LeetCode(110)平衡二叉树 题目 代码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(…

计算机二级C语言的注意事项及相应真题-6-程序填空

目录 51.将参数num按升序插入到数组xx中52.在数组中找出两科成绩之和最高的学生并返回其在数组中的下标53.删除所有串长超过k的字符串&#xff0c;输出剩下的字符串54.根据所给的一组学生的成绩&#xff0c;计算出平均成绩&#xff0c;并计算低于平均成绩的学生的平均成绩55.将…

python连接activemq

安装使用到的库 输入如下命令安装stomp pip install stomp.py 发送请求 # -*-coding:utf-8-*-import stomp import time# 队列名(接收方可以根据管道名来选择接受那个队列数据) location_queue "123456" # 服务器ip,端口固定用这个 conn stomp.Connection([(127…

AlexNet,ZFNet详解

1 AlexNet 网络结构 对于AlexNet网络来说&#xff0c;因为当时资源环境受限&#xff0c;他从第一步卷积开始就把一个图像分到两个GPU上训练&#xff0c;然后中间进行组合最后进行融合成全连接成1000个置信度 1 得到一张3x224x224的图像&#xff0c;然后进行11x11的卷积&…

山海鲸智慧医疗解决方案:让医疗数据说话

在医疗领域&#xff0c;数据可视化对于提高诊疗效率、辅助医学研究和提升患者就医体验具有重要意义。作为山海鲸可视化软件的开发者&#xff0c;我们致力于利用先进的数据可视化技术&#xff0c;为医疗行业提供高效、智能的解决方案&#xff0c;本篇文章就带大家一起了解一下这…

03 创建图像窗口的几种方式

read_image(Image, printer_chip/printer_chip_01) * 打开图像窗口 *用来打开一个新的图形窗口&#xff0c;可以用来显示图标对象&#xff0c;如图像、区域和线条&#xff0c;也可以执行文本输出。 *该窗口自动变为活动状态&#xff0c;所有所有输出(dev_display和自动显示操作…

pdf 转html 在线预览和查询

方案一&#xff1a;pdf2htmlex package com.realize.controller;import cn.hutool.http.HttpUtil; import com.alibaba.fastjson2.JSONObject; import com.realize.util.MsgUtil; import com.realize.util.OssUtil; import com.realize.util.PdfConvertUtil; import com.reali…

java大数据hadoop2.9.2 hive操作

1、创建常规数据库表 &#xff08;1&#xff09;创建表 create table t_stu2(id int,name string,hobby map<string,string> ) row format delimited fields terminated by , collection items terminated by - map keys terminated by :; &#xff08;2&#xff09;创…

【Linux】开始使用 vim 吧!!!

Linux 1 what is vim &#xff1f;2 vim基本概念3 vim的基本操作 &#xff01;3.1 vim的快捷方式3.1.1 复制与粘贴3.1.2 撤销与剪切3.1.3 字符操作 3.2 vim的光标操作3.3 vim的文件操作 总结Thanks♪(&#xff65;ω&#xff65;)&#xff89;感谢阅读下一篇文章见&#xff01;…

Power ModeII 插件的下载与使用-----idea

下载 Marketplace里面搜索下载即可 使用 下载后重启软件就可以用了 下面是一些关于Power ModeII &#xff0c;我的个性化设置截图 以及相关设置解释 插件或扩展的设置面板【用于给代码编辑器或集成开发环境&#xff08;IDE&#xff09;添加视觉效果】 主要设置 ENTER POWE…

力扣0092——反转链表II

反转链表II 难度&#xff1a;中等 题目描述 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 示例1 输入&#xff1a; head [1,2,3,4,5], left 2,…

数学知识第三期 欧拉函数

前言 相信大家在高中的时候接触过欧拉函数&#xff0c;希望大家通过本篇文章能够进一步理解欧拉函数&#xff01;&#xff01;&#xff01; 一、什么是欧拉函数&#xff1f; 欧拉函数是一个在数论中用于描述特定正整数的互质数的概念。具体来说&#xff0c;对于一个正整数n&…