Mahadeva
Mahadeva

Reputation: 1637

Running the program in background Wix

I have written a simple Installer that gets the value of property when I gave using following command:

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

I extracted the value of IPADDRESS in C# Custom action and created two folder output and config. In config, I write the content of IPADDRESS and output is for logging. Here's my C# code:

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;
        }
    }
}

Now I have created a Visual C++ application that checks if the program has been registered during startup or not. If not, it adds the exe file in Registry and enters the Infinite loop. If I run the installed exe, it appears in command window. What I want is to run the exe in background and user could view the exe inside Process in Task Manager. I don't want to disturb user by showing a blank terminal window that seems to do nothing. Can this be done in Wix or should I change my code? I have attached my C++ code and Wix File.

CODE

#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 FILE

<?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>

How am I supposed to install the MSI file and run the program in background.? Please help. PS: I have tried making a service. I do not get GetLocalAppDataPath true value if I run the program as service.

Upvotes: 0

Views: 548

Answers (2)

Christopher Painter
Christopher Painter

Reputation: 55581

All "RegisterMyProgramForStartup" is doing is writing a registry value. This is basic Windows Installer 101 functionality exposed by the RegistryValue element. All of this custom action code is an antipattern.

Upvotes: 0

dewaffled
dewaffled

Reputation: 2973

The straightforward way would be to change C++ application subsystem type to windows in project settings: Linker->System->SubSystem and replace main function with WinMain - it will not create any windows itself, you can ignore its parameters and do what you currently do in main.

Upvotes: 1

Related Questions