【问题标题】:Running the program in background Wix在后台运行程序 Wix
【发布时间】:2014-12-08 15:18:09
【问题描述】:

我编写了一个简单的安装程序,当我使用以下命令时,它会获取属性的值:

msiexec /i file.msi /l*v output.txt IPADDRESS="192.168.2.1"

我在 C# 自定义操作中提取了 IPADDRESS 的值,并创建了两个文件夹 output 和 config。在配置中,我写了 IPADDRESS 的内容,输出用于记录。这是我的 C# 代码:

namespace SetupCA
{
    public class CustomActions
    {
        [CustomAction]
        public static ActionResult WriteFileToDisk(Session session)
        {
            session.Log("Begin WriteFileToDisk");
            string ipAddress = session["IPADDRESS"];
            string path = session["LocalAppDataFolder"]; //With trailing slash
            path = path.Replace(@"\", @"\\").ToString();
            string log_path = path + @"lpa\\output\\";
            string config_path = path + @"lpa\\config\\";
            session.Log("Local App Data Modified Path is: " + path.ToString());
            session.Log("Logging Folder Path is: " + log_path.ToString());
            string temp = @"
{{
 ""logpoint_ip"" : ""{0}"" 
}}";
            string config = string.Format(temp, ipAddress);
            session.Log("Config Generated from property is: " + config);
            System.IO.Directory.CreateDirectory(config_path);
            try
            {
                System.IO.File.Delete(path + "lpa.config");
            }
            catch (Exception e)
            {
                session.Log(e.ToString());
            }
            System.IO.File.WriteAllText(config_path + "lpa.config", config);
            session.Log("Confile file is written");
            System.IO.Directory.CreateDirectory(log_path);
            session.Log("Logging Folder is Created");
            return ActionResult.Success;
        }
    }
}

现在我创建了一个 Visual C++ 应用程序,用于检查程序在启动期间是否已注册。如果没有,它会在注册表中添加 exe 文件并进入无限循环。如果我运行安装的 exe,它会出现在命令窗口中。我想要的是在后台运行exe,用户可以在任务管理器的进程中查看exe。我不想通过显示一个似乎什么都不做的空白终端窗口来打扰用户。这可以在 Wix 中完成还是应该更改我的代码? 我附上了我的 C++ 代码和 Wix 文件。

代码

#include <iostream>
#include <Windows.h>
#include <ShlObj.h>
#include <log4cplus/logger.h>
#include <log4cplus/fileappender.h>
#include <log4cplus/layout.h>
#include <log4cplus/ndc.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/loggingmacros.h>
#include <boost\lexical_cast.hpp>
#include <boost\algorithm\string\replace.hpp>
using namespace log4cplus;
Logger root;


std::string GetLocalAppDataPath();
void LoggingInit();

void LoggingInit()
{
        log4cplus::initialize ();
        helpers::LogLog::getLogLog()->setInternalDebugging(false);
        std::string local_path = GetLocalAppDataPath();
        local_path = local_path + "\\lpa\\output\\";
        SharedAppenderPtr append_1(new RollingFileAppender(LOG4CPLUS_TEXT( local_path + "outputgen.log"), 10*1024*1024, 5));
        append_1->setName(LOG4CPLUS_TEXT("LogpointAgentLog"));
        PatternLayout *p = new PatternLayout(LOG4CPLUS_TEXT("[%D] <%-5p> [%F : %L] %m%n"));
        append_1->setLayout(std::auto_ptr<Layout>(p));
        Logger::getRoot().addAppender(append_1);
        root = Logger::getRoot();
}

std::string GetLocalAppDataPath()
{
    HANDLE hfile;
    TCHAR szPath[MAX_PATH];
    if(SUCCEEDED(SHGetFolderPath(NULL,CSIDL_LOCAL_APPDATA,NULL,0, szPath))) 
    {
        std::string path = boost::lexical_cast<std::string>(szPath);
        boost::replace_all(path, "\\", "\\\\");
        return path;
    }
}


BOOL IsMyProgramRegisteredForStartup(PCWSTR pszAppName)
{
    HKEY hKey = NULL;
    LONG lResult = 0;
    BOOL fSuccess = TRUE;
    DWORD dwRegType = REG_SZ;
    wchar_t szPathToExe[MAX_PATH]  = {};
    DWORD dwSize = sizeof(szPathToExe);

    lResult = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_READ, &hKey);

    fSuccess = (lResult == 0);

    if (fSuccess)
    {
        lResult = RegGetValueW(hKey, NULL, pszAppName, RRF_RT_REG_SZ, &dwRegType, szPathToExe, &dwSize);
        fSuccess = (lResult == 0);
    }

    if (fSuccess)
    {
        fSuccess = (wcslen(szPathToExe) > 0) ? TRUE : FALSE;
    }

    if (hKey != NULL)
    {
        RegCloseKey(hKey);
        hKey = NULL;
    }

    return fSuccess;
}

BOOL RegisterMyProgramForStartup(PCWSTR pszAppName, PCWSTR pathToExe)
{
    HKEY hKey = NULL;
    LONG lResult = 0;
    BOOL fSuccess = TRUE;
    DWORD dwSize;

    const size_t count = MAX_PATH*2;
    wchar_t szValue[count] = {};


    wcscpy_s(szValue, count, L"\"");
    wcscat_s(szValue, count, pathToExe);
    wcscat_s(szValue, count, L"\" ");

    lResult = RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, NULL, 0, (KEY_WRITE | KEY_READ), NULL, &hKey, NULL);

    fSuccess = (lResult == 0);

    if (fSuccess)
    {
        dwSize = (wcslen(szValue)+1)*2;
        lResult = RegSetValueExW(hKey, pszAppName, 0, REG_SZ, (BYTE*)szValue, dwSize);
        fSuccess = (lResult == 0);
    }

    if (hKey != NULL)
    {
        RegCloseKey(hKey);
        hKey = NULL;
    }

    return fSuccess;
}

int main()
{
    //std::string loc = GetLocalAppDataPath(); //Without trailing slashes
    LoggingInit();  
    if(IsMyProgramRegisteredForStartup(L"My_Program"))
    {
        //do nothing
    }
    else
    {
        LOG4CPLUS_INFO(root, "Starting Starup App");
        wchar_t szPathToExe[MAX_PATH];
        GetModuleFileNameW(NULL, szPathToExe, MAX_PATH);
        RegisterMyProgramForStartup(L"My_Program", szPathToExe);
        LOG4CPLUS_INFO(root, "Ending Starup App");
    }

    LOG4CPLUS_INFO(root, "BEFORE INFINITE LOOP #######################");
    while(1)
    {
        LOG4CPLUS_INFO(root, "INSIDE THE WHILE LOOOOOOPPPP");
        Sleep(5000);
    }

    return 0;

}

WIX 文件

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Product Id="*" Name="InstallerForStartupCPP" Language="1033" Version="1.0.0.0" Manufacturer="LPAA" UpgradeCode="70510e56-b6ab-4e6f-beb6-40bb2e30c568">
        <Package InstallerVersion="200" Compressed="no" InstallScope="perMachine" />

        <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
        <MediaTemplate />

        <Feature Id="ProductFeature" Title="InstallerForStartupCPP" Level="1">
            <ComponentGroupRef Id="ProductComponents" />
        </Feature>
    </Product>

    <Fragment>
        <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="ProgramFilesFolder">
                <Directory Id="INSTALLFOLDER" Name="Startup CPP" />
            </Directory>
        </Directory>
    </Fragment>

    <Fragment>
        <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
      <Component Id="ProductComponent">
        <File
          Id="STARTUPCPPINSTALLER"
          Name="StartupCPPInstaller.exe"
          DiskId="1"
          Source="$(var.StartupCPPInstaller.TargetPath)"
          Vital="yes"
          KeyPath="yes" />
      </Component>

      <Component Id="log4cplus">
        <File Source ="G:\SarVaGYa\myworkspace\LatestLpa\lpa\lpa_c\ext_library\log4cplus\bin\Release\log4cplus.dll" />
      </Component>
        </ComponentGroup>
    <Binary Id="SetupCA"  SourceFile="..\SetupCA\bin\Release\SetupCA.CA.dll"/>
    <CustomAction Id="WRITEFILETODISK" Execute="immediate" BinaryKey="SetupCA" DllEntry="WriteFileToDisk" />
    <InstallExecuteSequence>
      <Custom Action="WRITEFILETODISK" Sequence="2"></Custom>
    </InstallExecuteSequence>
    </Fragment>
</Wix>

我应该如何安装 MSI 文件并在后台运行程序。?请帮忙。 PS:我已经尝试过提供服务。如果我将程序作为服务运行,我不会获得 GetLocalAppDataPath 真实值。

【问题讨论】:

  • 你到底想做什么?这对我来说似乎很鲁布戈德堡。这可能可以在 WiX 中完成,或者至少可以在不需要异步和等待进程外的自定义操作中完成。
  • 下面的 Frymode 显示它可以转换为 window 并且 main 可以包装在 WinMain 中。 Wix 如何处理同样的问题。任何可以为我指明方向的参考

标签: c# c++ visual-studio-2010 wix


【解决方案1】:

直接的方法是在项目设置中将 C++ 应用程序子系统类型更改为 windows:Linker-&gt;System-&gt;SubSystem 并将 main 函数替换为 WinMain - 它本身不会创建任何窗口,您可以忽略它的参数和做你目前在main做的事情。

【讨论】:

  • 还有一个问题。如何在 Wix 安装后立即运行 exe?
【解决方案2】:

“RegisterMyProgramForStartup”所做的只是写入一个注册表值。这是由 RegistryValue 元素公开的基本 Windows Installer 101 功能。所有这些自定义操作代码都是反模式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-10
    • 2011-09-11
    • 2018-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-02
    相关资源
    最近更新 更多