Reputation: 1637
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
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
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