Microsoft Installer 封装类
来源:互联网 发布:leap计算软件 编辑:程序博客网 时间:2024/06/05 21:57
制作 MSI 和控制 MSI 安装过程的封装类,该类是在线自动升级系统中发布工具和升级客户端的公共部分,具体代码如下:
//================================================================================================== // MSI 安装函数封装类( Microsoft Installer Wrapper Template Class ) // // 作者:王志科 版权没有,随意转载(请保留该文件头部信息) //================================================================================================== #pragma once #include "msi.h" #include "MsiDefs.h" #include "MsiQuery.h" #pragma comment(lib,"msi") #ifndef CHK_EXP_RET #define CHK_EXP_RET(exp,ret) if(exp){ return ret; } #define CHK_EXP_RUN(exp,run) if(exp){ run; } #endif namespace MSI { //============================================================================================== // template<bool tManage = true> class HandlerT { public: HandlerT(MSIHANDLE hMsi = NULL) : m_hMsi(hMsi) { } ~HandlerT() { if(tManage){ Close(); } } public: void Close(){ if(m_hMsi){ MsiCloseHandle(m_hMsi); m_hMsi = NULL; } } public: void Attach(MSIHANDLE hMsi){ ATLASSERT(m_hMsi != NULL); m_hMsi = hMsi; } MSIHANDLE Detach(){ MSIHANDLE hMsi = m_hMsi; m_hMsi = NULL; return hMsi; } public: void operator =(MSIHANDLE hMsi){ Close(); m_hMsi = hMsi; } MSIHANDLE* operator &() { Close(); return &m_hMsi; } operator MSIHANDLE() { return m_hMsi; } protected: MSIHANDLE m_hMsi; }; //============================================================================================== // template<bool tManage = true> class DatabaseT : public HandlerT<tManage> { public: DatabaseT(MSIHANDLE hDatabase = NULL) { m_hMsi = hDatabase; } DatabaseT(LPCTSTR lpszDatabase, LPCTSTR szPersist) { Open(lpszDatabase, szPersist); } public: UINT Open(LPCTSTR lpszDatabase, LPCTSTR szPersist) { return MsiOpenDatabase(lpszDatabase, szPersist, &m_hMsi); } VOID Close(BOOL bCommit = FALSE) { if(bCommit) Commit(); HandlerT::Close(); } UINT Commit() { return MsiDatabaseCommit(m_hMsi); } UINT Import(LPCTSTR szFolderPath,LPCTSTR szFileName) { return MsiDatabaseImport(m_hMsi,szFolderPath,szFileName); } UINT Export(LPCTSTR szTableName,LPCTSTR szFolderPath,LPCTSTR szFileName) { return MsiDatabaseExport(m_hMsi,szTableName,szFolderPath,szFileName); } UINT Merge(MSIHANDLE hDatabase, LPCTSTR szTableName) { return MsiDatabaseMerge(m_hMsi,hDatabase,szTableName); } UINT GenerateTransform(MSIHANDLE hDatabase, LPCTSTR szTransformFile) { return MsiDatabaseGenerateTransform(m_hMsi,hDatabase,szTransformFile,0,0); } UINT ApplyTransform(LPCTSTR szTransformFile, INT iErrorConditions) { return MsiDatabaseApplyTransform(m_hMsi,szTransformFile,iErrorConditions); } MSIDBSTATE GetState() { return MsiGetDatabaseState(m_hMsi); } MSICONDITION TableExists(LPCTSTR szTableName) { return MsiDatabaseIsTablePersistent(m_hMsi,szTableName); } MSICONDITION IsTablePersistent(LPCTSTR szTableName) { return MsiDatabaseIsTablePersistent(m_hMsi,szTableName); } // RecordT UINT PrimaryKeys(LPCTSTR szTableName, MSIHANDLE& hRecord) { return MsiDatabaseGetPrimaryKeys(m_hMsi,szTableName,&hRecord); } // View UINT OpenView(LPCTSTR szQuery, MSIHANDLE* pView) { return MsiDatabaseOpenView(m_hMsi,szQuery, pView); } // View UINT OpenExecuteView(LPCTSTR szQuery, MSIHANDLE* pView) { UINT nCaller = OpenView(szQuery, pView); CHK_EXP_RET(nCaller != ERROR_SUCCESS , nCaller); return MsiViewExecute(*pView, NULL); } }; //============================================================================================== // template<bool tManage = true> class RecordT : public HandlerT<tManage> { public: RecordT(UINT cParams = 3) { m_hMsi = MsiCreateRecord(cParams); } public: UINT GetFieldCount() { return MsiRecordGetFieldCount(m_hMsi); } BOOL IsNull(UINT iField) { return MsiRecordIsNull(m_hMsi,iField); } UINT SetNumber(UINT iField, INT iValue) { return MsiRecordSetInteger(m_hMsi,iField,iValue); } INT GetNumber(UINT iField) { return MsiRecordGetInteger(m_hMsi,iField); } BOOL GetString(UINT iField, CString& strValue) { DWORD dwValue = 4096; LPTSTR szValue = strValue.GetBuffer(dwValue); UINT nCaller = MsiRecordGetString(m_hMsi,iField,szValue,&dwValue); if(nCaller == ERROR_MORE_DATA) { dwValue += 2; strValue.ReleaseBuffer(); szValue = strValue.GetBuffer(dwValue); nCaller = MsiRecordGetString(m_hMsi,iField,szValue,&dwValue); } strValue.ReleaseBuffer(); return nCaller == ERROR_SUCCESS; } UINT GetString(UINT iField, LPTSTR szValue, LPDWORD dwValue) { return MsiRecordGetString(m_hMsi,iField,szValue,dwValue); } UINT SetString(UINT iField, LPCTSTR szValue) { return MsiRecordSetString(m_hMsi,iField,szValue); } UINT GetStream(UINT iField, LPSTR szBuffer,LPDWORD dwBuffer) { return MsiRecordReadStream(m_hMsi,iField,szBuffer,dwBuffer); } UINT SetStream(UINT iField, LPCTSTR szFilePath) { return MsiRecordSetStream(m_hMsi,iField,szFilePath); } }; //============================================================================================== // template<bool tManage = true> class ViewT : public HandlerT<tManage> { public: ViewT(MSIHANDLE hView = NULL) { m_hMsi = hView; } ViewT(MSIHANDLE hDatabase, LPCTSTR szQuery) { Open(hDatabase, szQuery); } public: UINT Open(MSIHANDLE hDatabase, LPCTSTR szQuery) { return MsiDatabaseOpenView(hDatabase,szQuery,&m_hMsi); } BOOL Execute(MSIHANDLE hRecord = NULL) { return MsiViewExecute(m_hMsi, hRecord); } UINT Fetch(MSIHANDLE& hRecord) { return MsiViewFetch(m_hMsi, &hRecord); } UINT Modify(MSIMODIFY eModify, MSIHANDLE hRecord) { return MsiViewModify(m_hMsi,eModify,hRecord); } UINT GetColumnInfo(MSICOLINFO eColumnInfo,MSIHANDLE& hRecord) { return MsiViewGetColumnInfo(m_hMsi,eColumnInfo,&hRecord); } // 执行了 Execute 之后,那么在下一次执行 Execute 之前必须调用该函数 UINT Release() { return MsiViewClose(m_hMsi); } }; template<bool tManage = true> class SummaryInformationT : public HandlerT<tManage> { public: SummaryInformationT(MSIHANDLE hDatabase, LPCTSTR szDatabase = NULL, UINT uiUpdateCount = 20) { Open(hDatabase,szDatabase, uiUpdateCount); } public: UINT GetPropertyCount(PUINT puiPropertyCount) { return MsiSummaryInfoGetPropertyCount(m_hMsi, puiPropertyCount); } UINT GetProperty(UINT uProperty,PUINT puiDataType,PINT piValue,PFILETIME pFileTime,LPTSTR szValue,LPDWORD dwValue) { return MsiSummaryInfoGetProperty(m_hMsi,uProperty,puiDataType,piValue,pFileTime,szValue,dwValue); } UINT SetProperty(UINT uProperty,UINT uDataType,INT iValue,PFILETIME pFileTime,LPTSTR szValue) { return MsiSummaryInfoSetProperty(m_hMsi,uProperty,uDataType,iValue,pFileTime,szValue); } UINT Open(MSIHANDLE hDatabase, LPCTSTR szDatabase = NULL, UINT uiUpdateCount = 20) { return MsiGetSummaryInformation(hDatabase,szDatabase, uiUpdateCount, &m_hMsi); } UINT Commit() { return MsiSummaryInfoPersist(m_hMsi); } public: UINT GetPropertyInteger(UINT uProperty,PINT piValue) { UINT uiDataType = VT_I4; return GetProperty(uProperty,&uiDataType,piValue,NULL,NULL,0); } UINT GetPropertyFiletime(UINT uProperty,PFILETIME pFileTime) { UINT uiDataType = VT_FILETIME; return GetProperty(uProperty,&uiDataType,NULL,pFileTime,NULL,0); } UINT GetPropertyString(UINT uProperty,LPTSTR szValue,LPDWORD dwValue) { UINT uiDataType = VT_LPSTR; return GetProperty(uProperty,&uiDataType,NULL,NULL,szValue,dwValue); } UINT SetPropertyInteger(UINT uProperty,INT iValue) { return SetProperty(uProperty,VT_I4,iValue,NULL,NULL); } UINT SetPropertyString(UINT uProperty,LPWSTR szValue) { return SetProperty(uProperty, VT_LPSTR, 0, NULL, szValue); } UINT SetPropertyFiletime(UINT uProperty,PFILETIME pFileTime) { return SetProperty(uProperty,VT_FILETIME,0,pFileTime,NULL); } public: VOID Close(BOOL bCommit = FALSE) { if(bCommit) Commit(); HandlerT::Close(); } }; //============================================================================================== // 安装控制函数 template<typename T = CWindow > struct InstallerT { public: InstallerT() { MemberInitialize(); m_nProgressBar = 0; m_nProcessInfo = 0; } ~InstallerT() { CancelInstaller(); } public: VOID CancelInstaller() { m_bCancelInstall = FALSE; } VOID SetExternalUI(DWORD dwMsgFilter) { MsiSetExternalUI(InstallerCallback, dwMsgFilter, (LPVOID)this); } UINT SetInternalUI(INSTALLUILEVEL nInstallerLevel, HWND* pWindow = NULL) { return MsiSetInternalUI(nInstallerLevel, pWindow); } // 在命令行中可以设置动作和属性,例如下面将产品安装到 D:/LiveSystem // TEXT("ACTION=INSTALL TARGETDIR=/"D://LiveSystem/"") UINT StartInstaller(LPCTSTR lpszPackage, LPCTSTR szCommandLine = NULL) { return MsiInstallProduct(lpszPackage, szCommandLine); } UINT SetControlID(UINT nProgressBar, UINT nProcessInfo = 0) { m_nProgressBar = nProgressBar; m_nProcessInfo = nProcessInfo; return ERROR_SUCCESS; } UINT SetScriptStringID(UINT nScriptStrID = 0) { m_nScriptStrID = nScriptStrID; return ERROR_SUCCESS; } public: // 采用默认参数安装指定的包 UINT InstallPackage(LPCTSTR lpszPackage, LPCTSTR pszCommand = NULL) { // 准备参数变量 DWORD dwUILevel = INSTALLUILEVEL_NONE|INSTALLUILEVEL_SOURCERESONLY; DWORD dwMessageFilter = INSTALLLOGMODE_USER | INSTALLLOGMODE_INFO | INSTALLLOGMODE_ACTIONDATA | INSTALLLOGMODE_OUTOFDISKSPACE | INSTALLLOGMODE_COMMONDATA | INSTALLLOGMODE_RESOLVESOURCE | INSTALLLOGMODE_INITIALIZE | INSTALLLOGMODE_ACTIONSTART | INSTALLLOGMODE_SHOWDIALOG | INSTALLLOGMODE_TERMINATE | INSTALLLOGMODE_FILESINUSE | INSTALLLOGMODE_PROGRESS | INSTALLLOGMODE_EXTRADEBUG | INSTALLLOGMODE_WARNING | INSTALLLOGMODE_FATALEXIT | INSTALLLOGMODE_ERROR; MemberInitialize(); SetExternalUI(dwMessageFilter); SetInternalUI((INSTALLUILEVEL)dwUILevel); return StartInstaller(lpszPackage, pszCommand); } public: // 下面的函数是消息回调 enum InstallerProgress { PROGRESS_RESET = 0, PROGRESS_ACTIONINFO = 1, PROGRESS_REPORT = 2, PROGRESS_ADDITION = 3, }; enum InstallerCommonData { COMMON_DATA_LANGUAGE = 0, COMMON_DATA_CAPTION = 1, COMMON_DATA_CANCELSHOW = 2, }; // premature termination, possibly fatal OOM INT OnInstallerFatalExit(UINT uFlags, LPCTSTR lpszMessage) { T* pT = static_cast<T*>(this); return pT->MessageBox(lpszMessage,m_strTitle, uFlags); } // formatted error message INT OnInstallerError(UINT uFlags, LPCTSTR lpszMessage) { T* pT = static_cast<T*>(this); return pT->MessageBox(lpszMessage, m_strTitle, uFlags); } // formatted warning message INT OnInstallerWarning(UINT uFlags, LPCTSTR lpszMessage) { T* pT = static_cast<T*>(this); return pT->MessageBox(lpszMessage, m_strTitle ,uFlags); } // user request message INT OnInstallerUser(UINT uFlags, LPCTSTR lpszMessage) { // 需要分析 uFlags 来确定返回 IDOK 或者 IDYES 或者其他值 return (uFlags & 0x0F) == MB_YESNO ? IDYES : IDOK; } // informative message for log INT OnInstallerInfo(UINT uFlags, LPCTSTR lpszMessage) { return IDOK; } // list of files in use that need to be replaced INT OnInstallerFilesInuse(UINT uFlags, LPCTSTR lpszMessage) { // 显示文件被使用的对话框 return ERROR_SUCCESS; } // request to determine a valid source location INT OnInstallerResolveSource(UINT uFlags, LPCTSTR lpszMessage) { return ERROR_SUCCESS; } // insufficient disk space message INT OnInstallerOutOfDiskSpace(UINT uFlags, LPCTSTR lpszMessage) { return IDOK; } // start of action: action name & description INT OnInstallerActionStart(UINT uFlags, LPCTSTR lpszMessage) { return IDOK; } // formatted data associated with individual action item INT OnInstallerActionData(UINT uFlags, LPCTSTR lpszMessage) { // 如果没有初始化进度条,直接返回 CHK_EXP_RET( m_nProgressTotal == 0 , IDOK ); T* pT = static_cast<T*>(this); pT->SetDlgItemText(m_nProcessInfo, lpszMessage); if( m_bEnableActionData && m_nProgressBar ) { HWND hProgressBar = pT->GetDlgItem(m_nProgressBar); SendMessage(hProgressBar, PBM_STEPIT, 0, 0); } return IDOK; } // progress gauge info: units so far, total INT OnInstallerProgress(UINT uFlags, LPCTSTR lpszMessage) { T* pT = static_cast<T*>(this); HWND hProgressBar = pT->GetDlgItem(m_nProgressBar); LONG nData[4] = { 0 , 0 , 0 , 0 }; if( ParseProgressString(lpszMessage, nData) ) { if(nData[0] == PROGRESS_RESET) { m_nProgressTotal = nData[1]; m_bProgressForward = (nData[2] == 0); m_nProgress = m_bProgressForward ? 0 : m_nProgressTotal ; // 设置进度条的工作长度 SendMessage(hProgressBar, PBM_SETRANGE32, 0, m_nProgressTotal); // 如果在处理脚本结束进度条,否则重置 WPARAM nCurrentPos = m_bProgressScript ? m_nProgressTotal : m_nProgress; SendMessage(hProgressBar, PBM_SETPOS, nCurrentPos , 0); m_nPosition = 0; // 检测新的状态 m_bProgressScript = (nData[3] == 1); if( m_bProgressScript && m_nProcessInfo && m_nScriptStrID ) { TCHAR szScriptString[MAX_PATH] = { TEXT("") }; AtlLoadString(m_nScriptStrID, szScriptString, MAX_PATH); pT->SetDlgItemText(m_nProcessInfo, szScriptString); } } else if(nData[0] == PROGRESS_ACTIONINFO ) { if( nData[2] && m_nProgressBar ) { WPARAM nStep = m_bProgressForward ? nData[1] : -1 * nData[1] ; SendMessage(hProgressBar, PBM_SETSTEP, nStep, 0); } m_bEnableActionData = nData[2] ? TRUE : FALSE ; } else if(nData[0] == PROGRESS_REPORT) { if( m_nProgressTotal != 0 ) { m_nPosition += nData[1]; WPARAM nCurrentPos = m_bProgressForward ? m_nPosition : -1 * m_nPosition; SendMessage(hProgressBar, PBM_SETPOS, nCurrentPos, 0); } } else if(nData[0] == PROGRESS_ADDITION) { } } return m_bCancelInstall ? IDCANCEL : IDOK ; } // product info for dialog: language Id, dialog caption INT OnInstallerCommonData(UINT uFlags, LPCTSTR lpszMessage) { ParseCommonDataString(lpszMessage); return IDOK; } // sent prior to UI initialization, no string data INT OnInstallerInitialize(UINT uFlags, LPCTSTR lpszMessage /* = NULL */) { return IDOK; } // sent after UI termination, no string data INT OnInstallerTerminate(UINT uFlags, LPCTSTR lpszMessage /* = NULL */) { return IDOK; } // sent prior to display or authored dialog or wizard INT OnInstallerShowDialog(UINT uFlags, LPCTSTR lpszMessage) { return IDOK; } public: INT OnInstallerPrepare(UINT uiMessageType, LPCTSTR lpszMessage) { if( m_bFirstTimeCall ) { MsiSetInternalUI(INSTALLUILEVEL_BASIC, NULL); m_bFirstTimeCall = FALSE; } return ERROR_SUCCESS ; } public: // 消息回调的处理函数 INT InstallerHandler(UINT uiMessageType, LPCTSTR lpszMessage) { T* pT = static_cast<T*>(this); // 首先允许进行特殊的消息处理 INT nPrepare = pT->OnInstallerPrepare(uiMessageType, lpszMessage); CHK_EXP_RET( FAILED( nPrepare ) , nPrepare ); // 根据消息类型进行分类处理 UINT uFlags = (uiMessageType & 0x00FFFFFF); switch( (INSTALLMESSAGE)(0xFF000000 & uiMessageType) ) { case INSTALLMESSAGE_FATALEXIT : return pT->OnInstallerFatalExit (uFlags, lpszMessage); case INSTALLMESSAGE_ERROR : return pT->OnInstallerError (uFlags, lpszMessage); case INSTALLMESSAGE_WARNING : return pT->OnInstallerWarning (uFlags, lpszMessage); case INSTALLMESSAGE_USER : return pT->OnInstallerUser (uFlags, lpszMessage); case INSTALLMESSAGE_INFO : return pT->OnInstallerInfo (uFlags, lpszMessage); case INSTALLMESSAGE_FILESINUSE : return pT->OnInstallerFilesInuse (uFlags, lpszMessage); case INSTALLMESSAGE_RESOLVESOURCE : return pT->OnInstallerResolveSource (uFlags, lpszMessage); case INSTALLMESSAGE_OUTOFDISKSPACE : return pT->OnInstallerOutOfDiskSpace(uFlags, lpszMessage); case INSTALLMESSAGE_ACTIONSTART : return pT->OnInstallerActionStart (uFlags, lpszMessage); case INSTALLMESSAGE_ACTIONDATA : return pT->OnInstallerActionData (uFlags, lpszMessage); case INSTALLMESSAGE_PROGRESS : return pT->OnInstallerProgress (uFlags, lpszMessage); case INSTALLMESSAGE_COMMONDATA : return pT->OnInstallerCommonData (uFlags, lpszMessage); case INSTALLMESSAGE_INITIALIZE : return pT->OnInstallerInitialize (uFlags, lpszMessage); case INSTALLMESSAGE_TERMINATE : return pT->OnInstallerTerminate (uFlags, lpszMessage); case INSTALLMESSAGE_SHOWDIALOG : return pT->OnInstallerShowDialog (uFlags, lpszMessage); } return ERROR_SUCCESS; } protected: static INT CALLBACK InstallerCallback(LPVOID lpContext, UINT uiMessageType, LPCTSTR lpszMessage) { InstallerT< T >* lpInstaller = reinterpret_cast< InstallerT< T >* >(lpContext); return static_cast<T*>(lpInstaller)->InstallerHandler(uiMessageType,lpszMessage); } protected: void MemberInitialize() { m_bShowCancel = TRUE; m_wLanguage = LANG_NEUTRAL; m_wCodePage = GetACP(); m_bProgressForward = TRUE; m_bProgressScript = FALSE; m_nProgressTotal = 0; m_nProgress = 0; m_nPosition = 0; m_bEnableActionData = FALSE; m_bCancelInstall = FALSE; m_bFirstTimeCall = TRUE; } protected: BOOL ParseCommonDataString(LPCTSTR lpString) { CHK_EXP_RET(lpString == NULL , FALSE ); CHK_EXP_RET(lpString[0] == 0 , FALSE ); // 分析字符串类型 lpString = StrStr(lpString, TEXT("1:")); CHK_EXP_RET(lpString == NULL , FALSE); LONG nCommon = lpString[3] - TEXT('0'); LPCTSTR lpStr2 = StrStr(lpString, TEXT("2:")); LPCTSTR lpStr3 = StrStr(lpString, TEXT("3:")); CHK_EXP_RET(lpStr2 == NULL , FALSE); if( nCommon == COMMON_DATA_CAPTION ) { LPTSTR lpTail = (LPTSTR)lpStr3; if(lpTail != NULL){ *lpTail = 0; } m_strTitle = lpString + 2; //Skip "2:" } else if( nCommon == COMMON_DATA_LANGUAGE ) { m_wLanguage = StrToLong(lpStr2 + 3); CHK_EXP_RET(lpStr3 == NULL , FALSE); m_wCodePage = StrToLong(lpStr3 + 3); } else if( nCommon == COMMON_DATA_CANCELSHOW ) { LONG nShow = StrToLong(lpStr2 + 3); m_bShowCancel = nShow ? TRUE : FALSE; } return TRUE; } BOOL ParseProgressString(LPCTSTR lpString, LONG nData[4]) { ZeroMemory( nData, sizeof(LONG) * 4 ); CHK_EXP_RET(lpString == NULL , FALSE ); CHK_EXP_RET(lpString[0] == 0 , FALSE ); // 分析字符串类型 lpString = StrStr(lpString, TEXT("1:")); CHK_EXP_RET(lpString == NULL , FALSE); nData[0] = lpString[3] - TEXT('0'); // 第一个参数 lpString = StrStr(lpString, TEXT("2:")); CHK_EXP_RET(lpString == NULL , TRUE); nData[1] = StrToLong(lpString + 3); // 第二个参数 lpString = StrStr(lpString, TEXT("3:")); CHK_EXP_RET(lpString == NULL , TRUE); nData[2] = StrToLong(lpString + 3); // 第三个参数 lpString = StrStr(lpString, TEXT("4:")); CHK_EXP_RET(lpString == NULL , TRUE); nData[3] = StrToLong(lpString + 3); return TRUE; } protected: // 下面是 CommonData 分析出的数据 CString m_strTitle; // 一般是安装的产品标题 BOOL m_bShowCancel; // 是否要显示“取消”按钮 WORD m_wLanguage; // 当前的语言 WORD m_wCodePage; // 当前的代码页 // 下面是 ProgressInfo 分析出的数据 BOOL m_bProgressForward; // TRUE 表示当前处理进度条是增加的方式 BOOL m_bProgressScript; // TRUE 表示在处理脚本,可以显示“请稍后” LONG m_nProgressTotal; // 进度条总数 LONG m_nProgress; // 进度数 LONG m_nPosition; // 当前位置 // 其他控制数据 BOOL m_bEnableActionData; // TRUE 表示 INSTALLOGMODE_ACTIONDATA 消息发送进度信息 BOOL m_bCancelInstall; // 如果要取消安装将该值设置为 TRUE BOOL m_bFirstTimeCall; // 是否第一次调用外部界面接口 // 窗口显示信息控件的ID UINT m_nProgressBar; // 进度条控件 UINT m_nProcessInfo; // 显示处理信息的控件 UINT m_nScriptStrID; // 处理脚本,请稍后 }; //============================================================================================== // 全局的静态函数 inline UINT GetFileHash(LPCTSTR lpszFileName, DWORD dwOptions, MSIFILEHASHINFO& rMsiFileHashInfo) { rMsiFileHashInfo.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO); return MsiGetFileHash(lpszFileName, dwOptions, &rMsiFileHashInfo); } inline UINT GetLastError(CString& strErrorDescription) { strErrorDescription = TEXT(""); MSIHANDLE hLastErrorRecord = MsiGetLastErrorRecord(); CHK_EXP_RET(hLastErrorRecord == NULL , NO_ERROR); DWORD dwErrorLength = 4096; HandlerT<> hRecord(hLastErrorRecord); UINT nCaller = MsiFormatRecord(NULL,hRecord,NULL,&dwErrorLength); if(nCaller == ERROR_MORE_DATA) { dwErrorLength ++; LPTSTR lpszError = new TCHAR[dwErrorLength]; nCaller = MsiFormatRecord(NULL,hRecord,lpszError,&dwErrorLength); if(nCaller == ERROR_SUCCESS) strErrorDescription = lpszError; delete [] lpszError; } return nCaller; } inline UINT GetFileVersion(LPCTSTR szFilePath, CString& strVersion, CString& strLanguage) { DWORD dwVersion = 32, dwLang = 32; LPTSTR lpszLang = strLanguage.GetBuffer(dwLang); LPTSTR lpszVersion = strVersion.GetBuffer(dwVersion); UINT nCaller = MsiGetFileVersion(szFilePath,lpszVersion, &dwVersion, lpszLang, &dwLang); if(nCaller == ERROR_MORE_DATA) { // 增加内存空间 dwLang += 2; dwVersion += 2; strVersion.ReleaseBuffer(); lpszVersion = strVersion.GetBuffer(dwVersion); strLanguage.ReleaseBuffer(); lpszLang = strLanguage.GetBuffer(dwLang); nCaller = MsiGetFileVersion(szFilePath,lpszVersion, &dwVersion, lpszLang, &dwLang); } else if(nCaller == ERROR_FILE_INVALID) { // 文件没有版本信息 nCaller = NO_ERROR; } strLanguage.ReleaseBuffer(); strVersion.ReleaseBuffer(); return nCaller; } }
- Microsoft Installer 封装类
- Microsoft Web Platform Installer介绍
- Microsoft VC++ runtime installer 问题解决
- .net异常microsoft windows installer 3.1
- Microsoft Web Platform Installer添加安装源
- Installer自定义安装类
- visual studio installer制作安装包——Installer 类
- 安装Microsoft Visual Studio 2008 SP1时出现无法访问Windows Installer服务的问题
- 使用Microsoft Web Platform Installer在windows平台搭建IIS+PHP+MySQL开发环境
- The Microsoft Visual J# 2.0 Second Edition installer returned error code '4113'
- 安装 postgresql 报错 "An error occured executing the Microsoft VC++ runtime installer"解决办法
- Microsoft .NET Framework 4.5.1 无法安装(Win7无法访问Windows Installer服务的解决方法)
- Microsoft Visual Studio 2015 Installer Projects无法显示桌面图标的问题
- Microsoft AJAX Library 对中JS的封装
- Windows Installer
- windows installer
- Windows Installer
- 封装类
- QT 用Windows的API函数,调用打开方式对话框
- jxl 解析EXCL (项目笔记)
- Spring1--浅谈
- 一个女人的爱情观
- Spring2--IoC
- Microsoft Installer 封装类
- iphone底部出现时间选择器(二)
- 类似于QQ,MSN的右下角消息弹出窗体,使用很简单
- Sqlite存储介绍
- 微软为硬件厂商描述基于Windows平台的商业机会
- 在Windows XP上安装Oracle11gR2时出错
- frameset的操作
- LinkedList,ArrayList和Vector
- The print command (Korn shell only)