Getting Application path during the installation - c#

I'm deploying an application and during the installation after the user chooses where to install the app, I want to get that path; I'm in a custom action already but i don't know how to get the application path where it's going to be installed !
It's Windows Forms and I'm developing using Visual studio 2010 "C#".
And I'm using the default deploying tool...
Any idea?
thanks in advance...

The class your custom action is in should inherit from System.Configuration.Installer.Installer. This has a parameter on it called Context which has a Parameters dictionary. The dictionary contains a number of useful variables about the install and you can add some.
Once you have added the custom installer to your install project in the Custom Actions pane. Select the Install action and set the CustomActionData property to:
/targetdir="[TARGETDIR]\"
Then you can access the path like this:
[RunInstaller(true)]
public partial class CustomInstaller : System.Configuration.Install.Installer
{
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
string path = this.Context.Parameters["targetdir"];
// Do something with path.
}
}

I know it's VB but This worked for me.
Private Sub DBInstaller_AfterInstall(ByVal sender As Object, ByVal e As System.Configuration.Install.InstallEventArgs) Handles Me.AfterInstall
MessageBox.Show(Context.Parameters("assemblypath"))
End Sub

Sorry to post answer for old post but my answer may help other.
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (rkApp.GetValue("MyApp") == null)
{
rkApp.SetValue("MyApp", this.Context.Parameters["assemblypath"]);
}
else
{
if (rkApp.GetValue("MyApp").ToString() != this.Context.Parameters["assemblypath"])
{
rkApp.SetValue("MyApp", this.Context.Parameters["assemblypath"]);
}
}
}
public override void Uninstall(System.Collections.IDictionary savedState)
{
base.Uninstall(savedState);
rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (rkApp.GetValue("MyApp") != null)
{
rkApp.DeleteValue("MyApp", false);
}
}

Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

Related

Can Caliburn.Micro be used for Visual Studio 2017 Extension Development?

I have been trying to use Caliburn.Micro in my extension that I am developing for Visual Studio 2017. I created my own custom bootstrapper. I used the example listed here Customer Bootstrapper. I kickstart my bootstrapper right after the extension's toolwindowpane is initialized. I have tried everything and it seems like I cannot get the Caliburn.Micro conventions to work. I am wondering if Caliburn.Micro can even work in an extension for Visual Studio!? The ToolWindowPane can host a WPF UserControl so I didn't think there would be an issue, but I cannot even get the ShellView to even see the ShellViewModel. Can someone let me know if Caliburn.Micro can work in this context???
Thanks!
Here is my BootStrapper:
public class ClassBootStrapper : BootstrapperBase<IShellViewModel>
{
private CompositionContainer container;
private static BootstrapperBase bootstrapper;
public static void Initialise()
{
if (null == bootstrapper)
{
bootstrapper = new ClassBootStrapper();
}
}
private ClassBootStrapper()
{
Initialize();
}
protected override IEnumerable<Assembly> SelectAssemblies()
{
var baseAssemblies = new List<Assembly>(base.SelectAssemblies());
var thisAssembly = Assembly.GetAssembly(typeof(ClassBootStrapper));
if (!baseAssemblies.Contains(thisAssembly))
{
baseAssemblies.Add(thisAssembly);
}
foreach (var assembly in baseAssemblies.ToList().Where(newAssembly => AssemblySource.Instance.Contains(newAssembly)))
{
baseAssemblies.Remove(assembly);
}
return baseAssemblies;
}
}
I test it in my side, it doesn't support the VS2017, you'd better to post the "Q & A" here:
https://marketplace.visualstudio.com/items?itemName=TheWinDev.CaliburnMicroWindows10Template#overview
So the extension team could provide much more helpful information for this extension.

Installer Custom action not working

I am trying to remove some additional files under the user profile Local Application Data folder after the uninstall of the app.
i read about custom action, so i wrote this
namespace RemoveUserAppDataCA
{
[RunInstaller(true)]
public partial class Installer1 : System.Configuration.Install.Installer
{
public Installer1()
{
InitializeComponent();
}
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
public override void Uninstall(IDictionary savedState)
{
base.Uninstall(savedState);
// Very important! Removes all those nasty temp files.
DeleteUserDataProfile();
base.Dispose();
}
void DeleteUserDataProfile()
{
try
{
string path = Path.GetFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "..\\MyCompanyFolder"));
if (Directory.Exists(path))
{
Directory.Delete(path,true);
}
}
catch (Exception)
{
throw;
}
}
}
}
I added the dll file to the project setup , then a added a custom actions , then under the uninstall , i added the ddl file of the RemoveUserAppDataCA . i built the system.
i did the installation , but when i uninstall the app the app folderthe user profile Local Application Data remains (does not get deleted).
What is wrong about the work ??
I found the problem , the folder path was wrong. The system was pointing at
"C:\Users\UserName\AppData\App_Folder" instead of "C:\Users\UserName\AppData\Local\App_Folder"

Write device platform specific code in Xamarin.Forms

I have the following Xamarin.Forms.ContentPage class structure
public class MyPage : ContentPage
{
public MyPage()
{
//do work to initialize MyPage
}
public void LogIn(object sender, EventArgs eventArgs)
{
bool isAuthenticated = false;
string accessToken = string.Empty;
//do work to use authentication API to validate users
if(isAuthenticated)
{
//I would to write device specific code to write to the access token to the device
//Example of saving the access token to iOS device
NSUserDefaults.StandardUserDefaults.SetString(accessToken, "AccessToken");
//Example of saving the access token to Android device
var prefs = Application.Context.GetSharedPreferences("MySharedPrefs", FileCreationMode.Private);
var prefsEditor = prefs.Edit();
prefEditor.PutString("AccessToken", accessToken);
prefEditor.Commit();
}
}
}
I would like to write platform specific code in the MyPage LogIn method to save the access token based on which device OS they are using my application on.
How do I only run device specific code when the user uses my application on their device?
This is a scenario which is easily resolved with dependency injection.
Have a interface with the desired methods on your shared or PCL code, like:
public interface IUserPreferences
{
void SetString(string key, string value);
string GetString(string key);
}
Have a property on your App class of that interface:
public class App
{
public static IUserPreferences UserPreferences { get; private set; }
public static void Init(IUserPreferences userPreferencesImpl)
{
App.UserPreferences = userPreferencesImpl;
}
(...)
}
Create platform-specific implementations on your target projects:
iOS:
public class iOSUserPreferences : IUserPreferences
{
public void SetString(string key, string value)
{
NSUserDefaults.StandardUserDefaults.SetString(value, key);
}
public string GetString(string key)
{
return NSUserDefaults.StandardUserDefaults.StringForKey(key);
}
}
Android:
public class AndroidUserPreferences : IUserPreferences
{
public void SetString(string key, string value)
{
var prefs = Application.Context.GetSharedPreferences("MySharedPrefs", FileCreationMode.Private);
var prefsEditor = prefs.Edit();
prefEditor.PutString(key, value);
prefEditor.Commit();
}
public string GetString(string key)
{
(...)
}
}
Then on each platform-specific project create an implementation of IUserPreferences and set it using either App.Init(new iOSUserPrefernces()) and App.Init(new AndroidUserPrefernces()) methods.
Finally, you could change your code to:
public class MyPage : ContentPage
{
public MyPage()
{
//do work to initialize MyPage
}
public void LogIn(object sender, EventArgs eventArgs)
{
bool isAuthenticated = false;
string accessToken = string.Empty;
//do work to use authentication API to validate users
if(isAuthenticated)
{
App.UserPreferences.SetString("AccessToken", accessToken);
}
}
}
Xamarin.Forms 2.3.4 introduced a new method for this:
if (Device.RuntimePlatform == Device.Android)
{
// Android specific code
}
else if (Device.RuntimePlatform == Device.iOS)
{
// iOS specific code
}
else if (Device.RuntimePlatform == Device.UWP)
{
// UWP specific code
}
There are also other platforms to choose from, you can type in Device. in Visual Studio and it will show you the options.
There are multiple answers, depending on what you want to achieve, and the kind of project you have:
Execute different Xamarin.Forms code on different platforms.
Use this e.g. if you want different font sizes on different platforms:
label.Font = Device.OnPlatform<int> (12, 14, 14);
Execute platform specific code in a shared (PCL) project
The common pattern is to use DI (dependency injection) for this. Xamarin.Forms provides a simple DependencyService for this, but use whatever you want.
Execute platform specific code in shared (Shared Asset Project) project
As the code is compiled per platform, you can wrap your platform specific code in #if __PLATFORM__ #endif and have all the code in the same file. The platform project should define __IOS__, __ANDROID__ and __WINDOWS_PHONE__. Note that a shared asset project containing Xaml and code won't work well for iOS on Xamarin.Studio, and that having compiler directives makes your code harder to read and to test.
Xamarin.Forms has a built-in dependency injector if you take a look at their guide in the developer area of their website (http://developer.xamarin.com/guides/cross-platform/xamarin-forms/dependency-service/)
There's also a wonderful library you can pull from NuGet/Github (https://github.com/aritchie/acr-xamarin-forms) that will handle the storage requirement you are looking for... take a look at the Settings service in there, it will even handle serialization of more complex objects.
This seems less about Xamarin.Forms and more about using defaults in a PCL. Check out James Montemagno's github repo for doing cross-platform defaults.
Then just call his static methods for setting/retrieving. The nuget package is Xam.Plugins.Settings.
It can be used like this:
using Refractored.Xam.Settings;
...
CrossSettings.Current.AddOrUpdateValue("AccessToken", accessToken);
var value = CrossSettings.Current.GetValueOrDefault<string>("AccessToken");

Prevent view caching in Nancy when using the Spark template engine

I'm using a self-hosted Nancy with Spark templates. I've disabled the cache specifically (though in DEBUG is should be disabled by default).
protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, IPipelines pipelines)
{
base.ApplicationStartup(container, pipelines);
...
StaticConfiguration.Caching.EnableRuntimeViewDiscovery = true;
StaticConfiguration.Caching.EnableRuntimeViewUpdates = true;
}
However, making changes to the templates while the app is running doesn't seem to work, as the template changes are not picked up.
Is there anything else required to disable views caching?
Since you're application is self hosted, I'm guessing you've either overriden the view location convention to find views as embedded resources in your assembly or have configured your Visual Studio project to copy views into the output directory at compile time. In both cases your application is not running off the view files you have in the Visial Studio project, but rather off copies of them. In that case caching is not the issue.
Ok, managed to get this to work by adding a custom ViewCache in the bootstrapper:
public class MyBootstrapper : DefaultNancyBootstrapper
{
#if DEBUG
protected override IRootPathProvider RootPathProvider
{
get
{
// this sets the root folder to the VS project directory
// so that any template updates in VS will be picked up
return new MyPathProvider();
}
}
protected override NancyInternalConfiguration InternalConfiguration
{
get
{
return NancyInternalConfiguration.WithOverrides(
x =>
{ x.ViewCache = typeof(MyViewCache); });
}
}
#endif
The new ViewCache just reloads the template on every request:
public class MyViewCache : IViewCache
{
...
public TCompiledView GetOrAdd<TCompiledView>(
ViewLocationResult viewLocationResult, Func<ViewLocationResult, TCompiledView> valueFactory)
{
//if (viewLocationResult.IsStale())
// {
object old;
this.cache.TryRemove(viewLocationResult, out old);
// }
return (TCompiledView)this.cache.GetOrAdd(viewLocationResult, x => valueFactory(x));
}
}
Somehow the viewLocationResult.IsStale() was always returning false.
By default, this is an instance of FileSystemViewLocationResult which just compares the last update time of the view, but the timestamp this.lastUpdated was being updated before calling IsStale() from the DefaultViewCache, so the template was never removed from the cache
public override bool IsStale()
{
return this.lastUpdated != this.fileSystem.GetLastModified(this.fileName);
}

WinRT 8.1 settings in Caliburn.Micro

I'm trying to open a settings view in a Caliburn.Micro WinRT 8.1 app using VS2013 RC, but I keep getting an unhandled exception when opening it with the following message:
Value cannot be null. Parameter name: Could not parse the VisualElements from the app manifest.
I can reproduce the issues with the following steps:
create a new Windows Store app from VS2013 RC using the Blank app template.
add Caliburn.Micro via NuGet.
in App.xaml, change the base class to caliburn:CaliburnApplication (the namespace is declared as xmlns:caliburn="using:Caliburn.Micro").
in App.xaml.cs, change the class like this (for the CM-based settings I follow http://compiledexperience.com/blog/posts/settings-caliburn)
Code below:
public sealed partial class App
{
private WinRTContainer _container;
public App()
{
InitializeComponent();
}
protected override void Configure()
{
_container = new WinRTContainer();
_container.RegisterWinRTServices();
_container.PerRequest<MainViewModel>();
_container.PerRequest<SettingsViewModel>();
ISettingsService settings = _container.RegisterSettingsService();
settings.RegisterCommand<SettingsViewModel>("Test settings");
}
protected override object GetInstance(Type service, string key)
{
var instance = _container.GetInstance(service, key);
if (instance != null) return instance;
throw new Exception("Could not locate any instances.");
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
protected override void PrepareViewFirst(Frame rootFrame)
{
_container.RegisterNavigationService(rootFrame);
}
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
DisplayRootView<MainView>();
}
}
Finally, create folders for Views and ViewModels in the solution add add to them the required items: MainViewModel, SettingsViewModel, MainView, SettingsView. The views just include a TextBlock with some text. MainViewModel derives from Screen, while SettingsViewModel derives from PropertyChangedBase. There is no relevant code in any of them.
When launching the app, I can see the main view; then I open the charms bar and click settings, and I find the label leading to my app settings; when I click it, I get the exception quoted above. Any hint?
You can find a full repro solution here: http://sdrv.ms/18GIMvB .
If you aren't ready to move to the alpha version of CM, you can update Callisto to 1.4.0 via NuGet. That fixed the error for me.
It seems that the new CM release (alpha 2) fixed the issue, so I'm adding some more information here to help other newcomers like me. Here is what I'm doing now:
In app's Configure I have some bootstrap code like:
...
ResourceLoader loader = ResourceLoader.GetForViewIndependentUse("Resources");
ISettingsService settings = _container.RegisterSettingsService();
settings.RegisterFlyoutCommand<ContentSettingsViewModel>(loader.GetString("SettingsContent"));
The ContentSettingsViewModel is a viewmodel for filtering some contents. The string got from resources is the label which will appear in the settings flyout (be sure there is an entry for this string, as passing an empty or null string triggers an exception). This VM is derived from CM Screen as I'm overriding OnActivate and OnDeactivate to load and save settings when the user opens or dismisses the settings page.

Categories

Resources