OZ_*_*_CM 3 c# installation windows-services visual-studio topshelf
我有 Visual Studio 2017,并且刚刚添加了Microsoft Visual Studio 安装程序项目扩展。我想要添加到安装程序的项目是由Topshelf构建的 Windows 服务应用程序。
要手动安装 Windows 服务,我以管理员身份打开 CMD 窗口,并在应用程序文件夹(例如 bin/debug)中运行命令来安装 Windows 服务应用程序。
现在,我确信安装程序没有方便的功能来安装服务,因为它唯一做的事情(简单来说)就是将一些文件放入目标目录中。
安装程序是否可以选择在安装完成后运行一些代码?如果没有,还有哪些替代方案?
您可以将“自定义操作”添加到安装程序项目的各个阶段。在解决方案资源管理器中右键单击该项目,然后选择:“查看 -> 自定义操作”。然后,您可以添加一个 DLL(您已构建 - 见下文 - 并安装在目标 PC 上)以在该过程中的各个点“执行”。
添加 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;
}
Run Code Online (Sandbox Code Playgroud)
ShellExecuteEx如果您已经知道要运行什么程序,您可能可以简化为仅部分。
习惯添加和定义此类自定义操作可能是一个陡峭的学习曲线,但大多数事情最终都可以通过坚持不懈(以及大量止痛药)来实现。
| 归档时间: |
|
| 查看次数: |
3225 次 |
| 最近记录: |