Running the program in background Wix - c#

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.

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.

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.

Related

UWP application unable to access USB drive even though permissions are set

I am working on an app that is responsible for formatting a USB drive and prepare it for further use on an embedded system.
I am formatting the drive using the following method that I found on stack overflow (unfortunately I did not save the link. I'll post it there if I find it again)
public static bool FormatUSB(string driveLetter, string fileSystem = "FAT32", bool quickFormat = true,
int clusterSize = 4096, string label = "USB_0000", bool enableCompression = false)
{
//add logic to format Usb drive
//verify conditions for the letter format: driveLetter[0] must be letter. driveLetter[1] must be ":" and all the characters mustn't be more than 2
if (driveLetter.Length != 2 || driveLetter[1] != ':' || !char.IsLetter(driveLetter[0]))
return false;
//query and format given drive
//best option is to use ManagementObjectSearcher
var files = Directory.GetFiles(driveLetter);
var directories = Directory.GetDirectories(driveLetter);
foreach (var item in files)
{
try
{
File.Delete(item);
}
catch (UnauthorizedAccessException) { }
catch (IOException) { }
}
foreach (var item in directories)
{
try
{
Directory.Delete(item);
}
catch (UnauthorizedAccessException) { }
catch (IOException) { }
}
ManagementObjectSearcher searcher = new ManagementObjectSearcher(#"select * from Win32_Volume WHERE DriveLetter = '" + driveLetter + "'");
foreach (ManagementObject vi in searcher.Get())
{
try
{
var completed = false;
var watcher = new ManagementOperationObserver();
watcher.Completed += (sender, args) =>
{
Console.WriteLine("USB format completed " + args.Status);
completed = true;
};
watcher.Progress += (sender, args) =>
{
Console.WriteLine("USB format in progress " + args.Current);
};
vi.InvokeMethod(watcher, "Format", new object[] { fileSystem, quickFormat, clusterSize, label, enableCompression });
while (!completed) { System.Threading.Thread.Sleep(1000); }
}
catch
{
}
}
return true;
}
I also added all the capabilities that should be required (I think) in order to access a removable drive in my manifest:
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:iot="http://schemas.microsoft.com/appx/manifest/iot/windows10"
IgnorableNamespaces="uap mp rescap iot">
<Identity
Name="7b9becad-6afd-4872-bcb7-7f414c098edf"
Publisher="CN=vitto"
Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="7b9becad-6afd-4872-bcb7-7f414c098edf" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>DiskMakerApp</DisplayName>
<PublisherDisplayName>vitto</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="DiskMakerApp.App">
<uap:VisualElements
DisplayName="DiskMakerApp"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png"
Description="DiskMakerApp"
BackgroundColor="transparent">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png"/>
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="broadFileSystemAccess" />
<rescap:Capability Name="appCaptureSettings" />
<Capability Name="internetClient" />
<uap:Capability Name="removableStorage" />
<iot:Capability Name="systemManagement"/>
<DeviceCapability Name="usb"/>
</Capabilities>
</Package>
And also allowed access to the file system in Window's settings page:
But I am still getting:
I am wondering if I am missing anything. Is there a way I could run the app as an administrator^ Would that solve the issue? (In any case, only admins would be able to run that app in a real life scenario)
UWP application unable to access USB drive even though permissions are set
Directory.GetFiles can't not use to access file with path in UWP platform. And you can only use Windows Storage API to access file with path (enable broadFileSystemAccess ), by the way, System.Management Namespace is not work for UWP platform, and if you want to format USB device within UWP app, please use desktop extension to process. for more please refer stefan' blog UWP with Desktop Extension

Showing PDF-File with MVVM Cross on Android and IOS

I want to open a PDF on the Phone via the File-Path but i cant figure out how i could do this properly without using 3rd party packages.
You have any suggestion for this?
I already tried to use this on Android:
public void OpenFile(string filePath)
{
var fileToOpen = new Java.IO.File(filePath);
var uri = FileProvider.GetUriForFile(Application.Context, Application.Context.PackageName + ".fileprovider", fileToOpen);
var intent = new Intent();
var mime = IOUtil.GetMimeType(uri.ToString());
intent.SetAction(Intent.ActionView);
intent.SetDataAndType(uri, mime);
intent.SetFlags(ActivityFlags.NewTask);
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
Application.Context.StartActivity(intent);
}
But i get the following Error:
Unhandled Exception:
Java.Lang.NullPointerException: Attempt to invoke virtual method
'android.content.res.XmlResourceParser
android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager,
java.lang.String)' on a null object reference
first you should addd this code to your manifest file :
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.easyphotopicker.fileprovider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths"
tools:replace="android:resource"/>
</provider>
and create filepaths :
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<root-path name="root" path="" /> //root directory of the device new File("/");
<files-path name="files" path="" /> //context.getFilesDir()
<cache-path name="cache" path="" /> //context.getCacheDir()
<external-path name="external" path="" /> //Environment.getExternalStorageDirectory()
<external-files-path name="name" path="path" /> //context.getExternalFilesDirs()
<external-cache-path name="name" path="path" /> //getExternalCacheDirs()
</paths>
Your error is telling us that there is no file at the location matching that's passed into the function. There's a few ways of doing this, one of them is as shown. After accepting permissions to access folders and files, this should be one of the simplest ways. You seem to be close:
public void OpenPdfFile(string filename)
{
var f = new Java.IO.File(filename);
if (f.Exists())
{
System.Diagnostics.Debug.WriteLine("File exists!");
try
{
var openFileIntent = new Intent(Intent.ActionView);
openFileIntent.SetDataAndType(Android.Net.Uri.FromFile(f), "application/pdf");
openFileIntent.SetFlags(ActivityFlags.NoHistory);
StartActivity(Intent.CreateChooser(openFileIntent, "Open pdf file"));
}
catch (ActivityNotFoundException)
{
//handle when no available apps
}
}
}
I haven't tested your work, but the first thing would be to see if you added this to the Manifest file
android:authorities="com.{package}.{name}.fileprovider"
since your code says Application.Context.PackageName + ".fileprovider"

Wix Toolset confirmation dialog before exit

I am developing an installation msi file using Wix toolset (in VS 2012) and faced with the problem that I can't add a confirmation dialog when user press button 'Cancel'. I tried to add also custom action dll with the message box, but if the function returns ActionResult.Failure, then my setup shows error dialog.
Original control:
<Control Type="PushButton" Id="progressCancelBtn" Width="56" Height="17" X="296" Y="244">
<Text>Cancel</Text>
<Publish Event="EndDialog" Value="Exit" />
</Control>
Try number 1:
public class CustomActions
{
[CustomAction]
public static ActionResult ShowExitMessageBox(Session session)
{
DialogResult result = MessageBox.Show("Exit installation?", "Exit", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
return ActionResult.Failure;
}
else
{
return ActionResult.Success;
}
}
}
Custom action:
<CustomAction Id='ShowExitMsgBox' BinaryKey='CustomActions' DllEntry='ShowExitMessageBox' Execute='immediate' Return='ignore'/>
<Binary Id='CustomActions' SourceFile='$(var.CASourcesPath)\CustomActions.CA.dll'/>
And tried to use:
<Control Type="PushButton" Id="cancelBtn" Width="56" Height="17" X="300" Y="244" Cancel="yes">
<Text>Cancel</Text>
<Publish Event="DoAction" Value="ShowExitMsgBox">1</Publish>
<!--Publish Event="EndDialog" Value="Exit" /-->
</Control>
But it shows like failure, instead of cancellation.
Thank you for help in advance.
Update:
I changed my custom action C# code to the next:
public class CustomActions
{
[CustomAction]
public static ActionResult ShowExitMessageBox(Session session)
{
DialogResult result = MessageBox.Show("Exit installation?", "Exit", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
session["CANCELEDPROP"] = "1";
}
else
{
session["CANCELEDPROP"] = "0";
}
return ActionResult.Success;
}
}
and WIX part:
// in Product.wxs
<Property Id="CANCELEDPROP" Secure="yes">0</Property>
// in UIFile.wxs
<Control Type="PushButton" Id="cancelBtn" Width="56" Height="17" X="300" Y="244" Cancel="yes">
<Text>Cancel</Text>
<Publish Event="DoAction" Value="ShowExitMsgBox">1</Publish>
<Publish Event="EndDialog" Value="Exit">CANCELEDPROP=1</Publish>
</Control>
It works on the first page, but I get an error on progress page: "Windows installer has stopped working" after I pressed some button on my message box. :(
I have found out if I don't use message box, then everything works. It is strange.
Update 2:
I tried to use session.Message instead of Windows.Forms, but message box just doesn't appear. Strange.
[CustomAction]
public static ActionResult ShowExitMessageBox(Session session)
{
Record record = new Record();
record.FormatString = "Exit installation?";
MessageResult result = session.Message(InstallMessage.Warning
| (InstallMessage)System.Windows.Forms.MessageBoxIcon.Warning
| (InstallMessage)System.Windows.Forms.MessageBoxButtons.YesNo,
record);
if (result == MessageResult.Yes)
{
session["CANCELEDPROP"] = "1";
}
else
{
session["CANCELEDPROP"] = "0";
}
return ActionResult.Success;
}
Finally I have found a solution by using CancelDlg from WixUIExtension.dll
(http://wixtoolset.org/documentation/manual/v3/wixui/dialog_reference/wixui_dialogs.html)
Add reference to WixUIExtension.dll (path on my computer is the next C:\Program Files (x86)\WiX Toolset v3.11\bin)
Add reference to icon that would be on the message box (Product.wxs):
< Binary Id="WixUI_Ico_Info" SourceFile="Images/MyIcon.ico" />
Control itself:
< Control Type="PushButton" Id="cancelBtn" Width="56" Height="17" X="300" Y="244" Cancel="yes">
< Text>Cancel
< Publish Event="SpawnDialog" Value="CancelDlg">1
< /Control>

How to add content file to Wix installer

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="MyApp" Language="1033" Version="1.0.0.0" Manufacturer="MyAppDev" UpgradeCode="067ac37f-0d36-4173-a24a-5037927bd6da">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature" Title="MyApp" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="MyApp" />
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
<!-- <Component Id="ProductComponent"> -->
<!-- TODO: Insert files, registry keys, and other resources here. -->
<!-- </Component> -->
<Component>
<File Source="$(var.MyApp.TargetPath)" />
</Component>
<Component>
<File Id="Postcodes.txt" Source="C:\Project\MyApp\MyApp\Files\Postcodes.txt" KeyPath="yes" />
</Component>
</ComponentGroup>
<Feature Id="MainApplication" Title="Main Application" Level="1">
<ComponentRef Id="Postcodes.txt" />
</Feature>
</Fragment>
</Wix>
My Windows form application using a text file which is stored in application directory. And with the help of WIX toolset. I have created an installer But the problem is content text file not exist. That's why i am getting File not found exception.
Please help me, How can i add this content text file to WIX installer? Or what would i need to add "Product.wxs" file?
You need to add a custom action. This is a direct copy of my work minus the company name that it was produced for.
<CustomAction Id="RestAction" BinaryKey="myCompanyAgentSetup.WixExtension.Package.dll" DllEntry="Execute" Execute="immediate" Return="check" />
This is a class file \ dll that is created in the Wix project. This is my actual dll \ class file
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Deployment.WindowsInstaller;
namespace myCompanyAgentSetup.WixExtension
{
public static class myCompanyAgentSetupWixExtension
{
[CustomAction]
public static ActionResult Execute(Session session)
{
var errorMsg = string.Empty;
var record = new Record();
var token = Environment.GetEnvironmentVariable("RX_JOB_NO");
var restUser = session["RESTUSER"];
var restPass = session["RESTPASS"];
var restUrl = string.Format(session["RESTURL"], token);
var request = (HttpWebRequest)WebRequest.Create(restUrl);
var encoded = Convert.ToBase64String(Encoding.Default.GetBytes(restUser + ":" + restPass));
request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + encoded);
request.Credentials = new NetworkCredential(restUser, restPass);
Console.WriteLine("attempting to get API Key");
try
{
var response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode.ToString() != "OK")
{
record = new Record
{
FormatString = string.Format(response.StatusDescription)
};
session.Message(InstallMessage.Error, record);
Console.WriteLine("Unable to get API Key");
Console.WriteLine("Adding RX_CLOUDBACKUP_API Environment Variable with no value");
UpdateConfigFiles("");
}
else
{
var apiKey = new StreamReader(response.GetResponseStream()).ReadToEnd();
if (apiKey.Contains("Error"))
{
record = new Record
{
FormatString = string.Format(apiKey)
};
session.Message(InstallMessage.Error, record);
session.Message(InstallMessage.Terminate, record);
}
Console.WriteLine("Adding RX_CLOUDBACKUP_API with value - " + apiKey);
UpdateConfigFiles(apiKey);
return ActionResult.Success;
}
}
catch (Exception e)
{
record = new Record
{
FormatString = string.Format(e.Message)
};
session.Message(InstallMessage.Error, record);
session.Message(InstallMessage.Terminate, record);
}
//An error has occurred, set the exception property and return failure.
session.Log(errorMsg);
session["CA_ERRORMESSAGE"] = errorMsg;
record = new Record
{
FormatString = string.Format("Something has gone wrong!")
};
session.Message(InstallMessage.Error, record);
session.Message(InstallMessage.Terminate, record);
return ActionResult.Failure;
}
private static void UpdateConfigFiles(string apiKey)
{
if (!string.IsNullOrEmpty(apiKey))
{
Environment.SetEnvironmentVariable("RX_CLOUDBACKUP_API", null, EnvironmentVariableTarget.Machine);
Environment.SetEnvironmentVariable("RX_CLOUDBACKUP_API", apiKey, EnvironmentVariableTarget.Machine);
}
else
{
Environment.SetEnvironmentVariable("RX_CLOUDBACKUP_API", "", EnvironmentVariableTarget.Machine);
}
}
}
}
Hopefully this will get you going. If you need anything else let me know

Associate a file extension to an application within C# application

I need to associate a file extension to a specific executable application and write its value in th register , so i see this tutorial :
tutorial
so i create a new Wpf application in which i add this class :
public class FileAssociation
{
// Associate file extension with progID, description, icon and application
public static void Associate(string extension,
string progID, string description, string icon, string application)
{
Registry.ClassesRoot.CreateSubKey(extension).SetValue("", progID);
if (progID != null && progID.Length > 0)
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(progID))
{
if (description != null)
key.SetValue("", description);
if (icon != null)
key.CreateSubKey("DefaultIcon").SetValue("", ToShortPathName(icon));
if (application != null)
key.CreateSubKey(#"Shell\Open\Command").SetValue("",
ToShortPathName(application) + " \"%1\"");
}
}
// Return true if extension already associated in registry
public static bool IsAssociated(string extension)
{
return (Registry.ClassesRoot.OpenSubKey(extension, false) != null);
}
[DllImport("Kernel32.dll")]
private static extern uint GetShortPathName(string lpszLongPath,
[Out] StringBuilder lpszShortPath, uint cchBuffer);
// Return short path format of a file name
private static string ToShortPathName(string longName)
{
StringBuilder s = new StringBuilder(1000);
uint iSize = (uint)s.Capacity;
uint iRet = GetShortPathName(longName, s, iSize);
return s.ToString();
}
}
Then, i added the icon image to the root of the project and i put this snippet :
if (!FileAssociation.IsAssociated(".akp"))
FileAssociation.Associate(".akp", "ClassID.ProgID", "akp File", "akeo.ico", #"C:\Users\Lamloumi\Desktop\MyWork\C#\App - SuiteTool\bin\x64\Debug\App - SuiteTool.exe");
But i got a problem here in this line
Registry.ClassesRoot.CreateSubKey(extension).SetValue("", progID);
So i need to know
What is the problem ie why this code didn't work?
How can i fix it?
Thanks,
Seems that you haven't enough permissions for writing in the windows registry
Try to add to project app.manifest file with content:
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</asmv1:assembly>
or if application have to work without requesting admin rights on each start add ability to self-elevate as shown in this example UAC self-elevation

Categories

Resources