Вы можете добавить «Пользовательские действия» на различные этапы вашего проекта установщика. Щелкните правой кнопкой мыши проект в обозревателе решений и выберите «Просмотр -> Пользовательские действия». Затем вы можете добавить DLL (которую вы построили — см. ниже — и установили на целевой ПК) для «выполнения» на различных этапах процесса.
Когда вы добавили DLL, вам нужно указать процедуру «Точка входа» (например, MSR202030202
в приведенном ниже примере) и (необязательно) «Данные настраиваемого действия» для передачи этой процедуре ([TARGETDIR]
— каталог установки — в образец кода).
Когда установщик достигнет этапа, на котором вы добавили DLL, он вызовет указанную точку входа с доступными данными.
Ниже приведен пример процедуры DLL, которая будет выполняться на этапе «Зафиксировать» установки. В этом примере будет сравниваться версия VC-Redistributable в целевом каталоге с любой текущей установленной и «порождающей» версией, если наша версия новее. Это довольно большой кусок кода, но мы надеемся, что он даст вам некоторое представление о том, что требуется.
extern "C" uint32_t __declspec(dllexport) __stdcall MSR202030202(MSIHANDLE hInst)
{
// First (default) action: Get the location of the installation (the destination folder) into "dstPath" variable...
DWORD dstSize = MAX_PATH; wchar_t dstPath[MAX_PATH]; MsiGetProperty(hInst, L"CustomActionData", dstPath, &dstSize);
CString regPath = L"SOFTWARE\\Microsoft\\VisualStudio\\14.0\\VC\\RunTimes\\";
#if defined(_M_X64)
wchar_t vcrFile[] = L"vc_redist.x64.exe"; regPath += L"x64";
#elif defined(_M_IX86)
wchar_t vcrFile[] = L"vc_redist.x86.exe"; regPath += L"x86";
#endif
CString vcrPath = CString(dstPath) + vcrFile;
// Get the version numbers of the VC Runtime Redistributable currently installed (from the registry) ...
WORD rVer[4] = { 0, 0, 0, 0 };
HKEY hKey; DWORD gotSize, gotType, gotData;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, regPath, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
gotSize = sizeof(DWORD);
if (RegQueryValueEx(hKey, L"Major", nullptr, &gotType, reinterpret_cast<BYTE *>(&gotData), &gotSize) == 0) {
if ((gotType == REG_DWORD) && (gotSize == sizeof(DWORD))) rVer[0] = LOWORD(gotData);
}
gotSize = sizeof(DWORD);
if (RegQueryValueEx(hKey, L"Minor", nullptr, &gotType, reinterpret_cast<BYTE *>(&gotData), &gotSize) == 0) {
if ((gotType == REG_DWORD) && (gotSize == sizeof(DWORD))) rVer[1] = LOWORD(gotData);
}
gotSize = sizeof(DWORD);
if (RegQueryValueEx(hKey, L"Bld", nullptr, &gotType, reinterpret_cast<BYTE *>(&gotData), &gotSize) == 0) {
if ((gotType == REG_DWORD) && (gotSize == sizeof(DWORD))) rVer[2] = LOWORD(gotData);
}
gotSize = sizeof(DWORD);
if (RegQueryValueEx(hKey, L"Rbld", nullptr, &gotType, reinterpret_cast<BYTE *>(&gotData), &gotSize) == 0) {
if ((gotType == REG_DWORD) && (gotSize == sizeof(DWORD))) rVer[3] = LOWORD(gotData);
}
RegCloseKey(hKey);
}
// Get the version numbers of the VC Redistributable provided with this installation (from the file) ...
WORD fVer[4] = { 0, 0, 0, 0 };
if (_waccess(vcrPath, 0) == 0) {
DWORD vHand, vSize = GetFileVersionInfoSize(vcrPath.GetString(), &vHand);
VS_FIXEDFILEINFO *vInfo = nullptr; unsigned vSiz2 = 0u;
if (vSize > 0) {
BYTE* vBuff = new BYTE[vSize]; vHand = 0;
BOOL vStat = GetFileVersionInfo(vcrPath.GetString(), vHand, vSize, vBuff);
if (vStat) vStat = VerQueryValue(vBuff, L"\\", reinterpret_cast<void **>(&vInfo), &vSiz2);
if (vStat && (vInfo != nullptr)) {
DWORD msdw = vInfo->dwFileVersionMS, lsdw = vInfo->dwFileVersionLS;
fVer[0] = HIWORD(msdw);
fVer[1] = LOWORD(msdw);
fVer[2] = HIWORD(lsdw);
fVer[3] = LOWORD(lsdw);
}
delete[] vBuff;
}
}
// Compare the two sets of version numbers to see if we need to run the installer ...
bool hasVCR = false;
if (rVer[0] > fVer[0]) hasVCR = true;
else if (rVer[0] == fVer[0]) {
if (rVer[1] > fVer[1]) hasVCR = true;
else if (rVer[1] == fVer[1]) {
if (rVer[2] >= fVer[2]) hasVCR = true;
// Don't bother checking the last ('rebuild') version!
}
}
if (!hasVCR) { // Set up a ShellExecute command to run the installer when this program exits ...
CString params = L"/q /norestart";
SHELLEXECUTEINFO shexInfo; memset(&shexInfo, 0, sizeof(SHELLEXECUTEINFO));
shexInfo.cbSize = sizeof(SHELLEXECUTEINFO);
shexInfo.fMask = SEE_MASK_DEFAULT;
shexInfo.lpFile = vcrPath.GetString();
shexInfo.lpParameters = params.GetString();
ShellExecuteEx(&shexInfo);
}
return ERROR_SUCCESS;
}
Вы, вероятно, можете упростить только часть ShellExecuteEx
, если вы уже знаете, какие программы вы хотите запустить.
Привыкание к добавлению и определению таких настраиваемых действий может быть крутым процессом обучения, но большинство вещей в конечном итоге могут быть достигнуты с настойчивостью (и хорошим запасом болеутоляющих средств).
person
Adrian Mole
schedule
31.12.2019