What is BrowserSubprocessPath? - chromium-embedded

I have CefSharp-master project with which is Built on Chromium- 31.0.1650.57. All is working fine and perfect. But while Initializing settings.BrowserSubprocessPath is set to an executable.
What is this BrowserSubprocessPath? what happen if I avoid this?
I am Initializing Cef as:
public static void Init()
{
var settings = new CefSettings();
settings.UserAgent = "MyBrowser";
if (!Cef.Initialize(settings))
{
if (Environment.GetCommandLineArgs().Contains("--type=renderer"))
{
Environment.Exit(0);
}
else
{
return;
}
}
}
This is working fine, Only after sometime browser window goes blank.What is the reason behind this.

When you set SingleProcess = false you should define sub-process executable file for it:
http://xilium.bitbucket.org/cefglue/doc/html/E3568E23.htm
So you can set SingleProcess = true (which is not recommended in production)
or set it to a sub-process file like cefclient.exe

Related

Convert FileInfo read file code to maui equivalent

I know I should know how to do this, but I don't.
I have some code (from a brilliant map routing packing called Itinero http://docs.itinero.tech/index.html) that reads in a a routerDb file.
It works great (in windows) if I use a fully qualified path as it is absolute, but I have moved the file into the Resources.Raw folder and want to read it properly.
The working code
using (var stream = new FileInfo(#"/path/to/my/file/gb.routerdb").OpenRead())
{
routerDb = RouterDb.Deserialize(stream);
}
How can I use the Maui approach to do the same thing? Such as or simpler
using (var stream = new xxx("gb.routerdb").xxxx)
{
routerDb = RouterDb.Deserialize(stream);
}
I'm looking at https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/storage/file-system-helpers?tabs=windows but I don't get it :(
Thanks for any help.
G.
As document Platform differences of File system helpers mentioned, you can use method FileSystem.OpenAppPackageFileAsync to access file in the Resources\Raw folder as a MauiAsset.
Besides, if you want to access the path of the items in folder Raw, you can follow up the unknown issue about this:
https://github.com/dotnet/maui/issues/7943 .
Update:
As a test, I created a simple html(test.html) in folder Resource\Raw, and set BuildAction to MauiAsset.And I used the following code to read the html, it works well on my side(I tested on android device).
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
private async Task InitAsync()
{
string filePath = "test.html";
#if WINDOWS
var stream = await FileSystem.OpenAppPackageFileAsync("Assets/" + filePath);
#else
var stream = await FileSystem.OpenAppPackageFileAsync(filePath);
#endif
if (stream != null)
{
string s = (new System.IO.StreamReader(stream)).ReadToEnd();
this.MyWebView.Source = new HtmlWebViewSource { Html = s };
}
}
private void OnClicked(object sender, EventArgs e)
{
InitAsync();
}
}
MainPage.xaml
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<WebView x:Name="MyWebView"
/>
<Button
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnClicked"
HorizontalOptions="Center" />
</VerticalStackLayout>
Well I certainly appreciate the example code, but for some reason it didn't work for me, but what did work based on your code (#Jessie Zhang) was:
var stream = await FileSystem.OpenAppPackageFileAsync("gb.routerdb");
if (stream != null)
{
routerDb = RouterDb.Deserialize(stream);
}
The conditional didn't work and I'm not sure why, but I'm only using windows so I'll check that out later. Thanks

Restore all layered pane components in their positions and repaint them

This question is related to this: Keep Codename One components in invalid positions after app stop/resume
In the linked question, the solution proposed is to use a fake layout. I tried that, but it produces side effects when I try to restore the original layouts.
I tried a completely different approach, that works fine on Android. My question is why the following code works well in Android only (it doesn't work on iPhone, that seems to ignore that code) and if there are small changes that make that code working also on iPhone.
The code:
private Map<Component, Dimension> layeredPaneCmps = new HashMap<>();
public void start() {
if (current != null) {
current.show();
layeredPaneRestore(); // it works on Android, but not on iOS
return;
}
[...]
}
public void stop() {
current = getCurrentForm();
if (current instanceof Dialog) {
((Dialog) current).dispose();
current = getCurrentForm();
}
layeredPaneSave(null);
}
/**
* Save the position of all layered pane components in a recursive way: just
* invoke with null as cnt.
*
* #param cnt
*/
private void layeredPaneSave(Container cnt) {
if (cnt == null) {
layeredPaneCmps.clear();
cnt = Display.getInstance().getCurrent().getLayeredPane(this.getClass(), true);
}
for (int i = 0; i < cnt.getComponentCount(); i++) {
layeredPaneCmps.put(cnt.getComponentAt(i), new Dimension(cnt.getComponentAt(i).getX(), cnt.getComponentAt(i).getY()));
if (cnt.getComponentAt(i) instanceof Container) {
layeredPaneSave((Container) cnt.getComponentAt(i));
}
}
}
/**
* Restores all layered pane components in their position and repaints them.
*/
private void layeredPaneRestore() {
Container layeredPane = Display.getInstance().getCurrent().getLayeredPane(this.getClass(), true);
for (Component cmp : layeredPaneCmps.keySet()) {
cmp.setX(layeredPaneCmps.get(cmp).getWidth());
cmp.setY(layeredPaneCmps.get(cmp).getHeight());
cmp.repaint();
}
layeredPane.repaint();
}
Android and iOS have very different suspend/resume behaviors where iOS tries to minimize repaints and back-grounding while Android constantly suspends/resumes. I would suggest logging in the stop()/start() method to make sure they aren't invoked multiple times.
Notice that you shouldn't invoke repaint() it would be invoked for you. Since a repaint() might trigger a layout this could be a problem. Also the repaint() of the parent component loops into painting the components so layeredPane would be enough and doesn't require also cmp.repaint();.

Proper way to upgrade WPF program settings on program update (Desktop Bridge/Project Centennial)

When it was a clickonce program it worked, but then I made an appxpackage and exported it as a centennial app for windows store and the upgrade does not work any more.
Right now I have in App.xaml.cs
protected override void OnStartup(StartupEventArgs e) {
if (myprog.Properties.Settings.Default.UpgradeRequired)
{
myprog.Properties.Settings.Default.Upgrade();
myprog.Properties.Settings.Default.UpgradeRequired = false;
myprog.Properties.Settings.Default.Save();
}
With UpgradeRequired as a bool in user settings. Is that the right place?
I am getting settings reset on each version update. Now I have several of these directories
C:\Users\me\AppData\Local\progname\prog.exe_Url_randomChars
each with several different version of program settings. So after the upgrade another one of those is created, instead a subfolder with x.x.x.x of the current version.
As before, on each version release I increase version in Assembly Information the Assembly Version, File Version, and now I have the same numbers in AppxManifest.xml. I keep the last number group of the version to 0 as advised, and just increase the 3rd number group.
Is there something I am missing?
UWP and Desktop Bridge apps need to store their settings in ApplicationData.LocalSettings:
https://learn.microsoft.com/en-us/windows/uwp/design/app-settings/store-and-retrieve-app-data#local-app-data
You could load the previous user.config file into current settings. This is just a workaround, and can be used to transition to ApplicationData.LocalSettings.
public static void Init()
{
if (myprog.Properties.Settings.Default.UpgradeRequired)
{
LoadPreviousSettings(myprog.Properties.Settings.Default);
myprog.Properties.Settings.Default.UpgradeRequired = false;
myprog.Properties.Settings.Default.Save();
}
}
private static void LoadPreviousSettings(params ApplicationSettingsBase[] applicationSettings)
{
const string companyName = "YOUR_COMPANY_NAME_HERE";
var userConfigXml = GetUserConfigXml(companyName);
Configuration config = ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.PerUserRoamingAndLocal);
foreach (ApplicationSettingsBase setting in applicationSettings)
{
try
{
// loads settings from user.config into configuration
LoadSettingSection(setting, config, userConfigXml);
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("userSettings");
}
catch (FileNotFoundException)
{
// Could not import settings.
// Perhaps user has no previous version installed
}
setting.Reload();
}
}
private static void LoadSettingSection(ApplicationSettingsBase setting, Configuration config, XDocument userConfigXml)
{
string appSettingsXmlName = setting.ToString();
var settings = userConfigXml.XPathSelectElements("//" + appSettingsXmlName);
config.GetSectionGroup("userSettings")
.Sections[appSettingsXmlName]
.SectionInformation
.SetRawXml(settings.Single().ToString());
}
private static XDocument GetUserConfigXml(string companyName)
{
var localPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + $#"\{companyName}";
// previous package folder
var previousLocal = GetDirectoryByWriteTime(localPath, 1);
// previous version, e.g. 1.2.0
var prevousVersion = GetDirectoryByWriteTime(previousLocal, 0);
// application settings for previous version
return XDocument.Load(prevousVersion + #"\user.config");
}
private static string GetDirectoryByWriteTime(string path, int order)
{
var direcotires = new DirectoryInfo(path).EnumerateDirectories()
.OrderBy(d => d.LastWriteTime)
.Reverse()
.ToList();
if (direcotires.Count > order)
{
var previous = direcotires[order];
return previous.FullName;
}
throw new FileNotFoundException("Previous config file not found.");
}
There is a working answer here.
Basically you need to create a duplicate version using UWP's ApplicationData.Settings and then loading it at the beginning of the app. It is very straightforward when your settings are strings, bools, etc. But not so if you have unique settings.
To elaborate more from the answer in the link, when you have settings consisting of custom types/classes, when creating UWP's duplicate version, you can use Newtonsoft.Json to serialise the custom setting:
try
{
ApplicationData.Current.LocalSettings.Values[value.Name] = value.PropertyValue;
}
catch
{
string serialised = JsonConvert.SerializeObject(value.PropertyValue);
ApplicationData.Current.LocalSettings.Values[value.Name] = serialised;
}
Then when loading your custom setting:
if (s.Name == "MyCustomSetting")
{
var deserialised = JsonConvert.DeserializeObject<MyCustomClass>((string)setting.Value);
s.PropertyValue = deserialised;
}

MVC5 DisplayModeProvider registration problems

so I have an mvc 5 application with 3 display modes, desktop (default), mobile, and tablet. I'm using WURFL to figure out devices. Here's the code called from global.cs to register:
public static void RegisterDisplayModes(IList<IDisplayMode> displayModes){
var datafile = HttpContext.Current.Server.MapPath(WurflDataFilePath);
var configurer = new InMemoryConfigurer().MainFile(datafile);
var manager = WURFLManagerBuilder.Build(configurer);
HttpContext.Current.Cache[WURFLMANAGER_CACHE_KEY] = manager;
bool mobileEnabled = ConfigurationManager.AppSettings["EnableMobileSite"] == "true";
bool tabletEnabled = ConfigurationManager.AppSettings["EnableTabletSite"] == "true";
var modeDesktop = new DefaultDisplayMode("") {
ContextCondition = (c => c.Request.IsDesktop())
};
var modeMobile = new DefaultDisplayMode("mobile"){
ContextCondition = (c => c.Request.IsMobile())
};
var modeTablet = new DefaultDisplayMode("tablet"){
ContextCondition = (c => c.Request.IsTablet())
};
displayModes.Clear();
if (mobileEnabled) displayModes.Add(modeMobile);
if (tabletEnabled) displayModes.Add(modeTablet);
displayModes.Add(modeDesktop);
}
I'm using some extension methods to HttpRequestBase, as discussed in http://msdn.microsoft.com/en-us/magazine/dn296507.aspx:
public static bool IsDesktop(this HttpRequestBase request){
return true;
}
public static bool IsMobile(this HttpRequestBase request) {
return IsMobileInternal(request.UserAgent) && !IsForcedDesktop(request);
}
public static bool IsTablet(this HttpRequestBase request) {
return IsTabletInternal(request.UserAgent) && !IsForcedDesktop(request);
}
public static void OverrideBrowser(this HttpRequestBase request, bool forceDesktop){
request.RequestContext.HttpContext.Cache[OVERRIDE_BROWSER_CACHE_KEY] = forceDesktop;
}
public static bool IsForcedDesktop(this HttpRequestBase request){
var isForced = request.RequestContext.HttpContext.Cache[OVERRIDE_BROWSER_CACHE_KEY];
return isForced != null ? isForced.ToString().ToBool() : false;
}
private static bool IsMobileInternal(string userAgent) {
var device = WURFLManagerBuilder.Instance.GetDeviceForRequest(userAgent);
if (device.IsTablet() == true) {
return false;
} else {
return device.IsMobile();
}
}
private static bool IsTabletInternal(string userAgent) {
var device = WURFLManagerBuilder.Instance.GetDeviceForRequest(userAgent);
return device.IsTablet();
}
It all works fine for a while, but then after an hour or so, mobile and tablet devices start displaying the desktop views, and the desktop view starts showing the ViewSwitcher shared view (I assume most people are familiar with it, it just allows you to show the desktop view from a mobile device). It's almost like that caching bug in mvc4. I have tried removing my code to register the display modes, and just went with the default mvc mobile support, and it works fine it has the same issue! So clearly there's a problem in here somewhere... can anyone see anything obvious? Almost impossible to debug cause problems only start coming up after a long time, and even then only on the live system really! Any ideas?
Thanks heaps... been on this issue for way too long now...
Cheers
Andy
EDIT: even stripping it right back to the default implementations creates the issue. I added some debugging code to make sure I'm actually running mvc5, but it appears I am. I've also tried the initially recommended workaround for the issue on mvc4 by disabling the cache, still no joy. Is there really no one with info on this?
So I finally figured it out. Very simple as usual. For some reason I used RequestContext.HttpContext.Cache to save the status when someone wants the full view as opposed to the mobile view. I've never used HttpContext.Cache, I'm pretty sure I would have taken that from a blog somewhere - can't find it anymore though. So all that happened was that it would switch the view for everyone, not just the one person. Can't believe it took weeks to figure that out. Hope it helps someone else at some point.

Isolated Storage Application Settings Not Persisting after Application exit

I'm having a big problem using WP7 isolated storage and applicationsettings.
I have been using code from Adam Nathan's 101 Windows Phone 7 apps volume 1 as a basis.
I have a settings page where values can be altered and whilst the application is still running these remain active and it all works perfectly. However, as soon as the app exits on my developer phone these are lost and the app restarts with the default settings.
I have no idea why these values are not persisting. Any help would be much appreciated.
Here is the code i've got, its from adam nathan's new book. I sent him a message on twitter and he said its to do with a data type that isn't serializable. I looked into this but i'm only using double and bool values.
public class Setting<T>
{
string name;
T value;
T defaultValue;
bool hasValue;
public Setting(string name, T defaultValue)
{
this.name = name;
this.defaultValue = defaultValue;
}
public T Value
{
get
{
//checked for cached value
if (!this.hasValue)
{
//try to get value from isolated storage
if (IsolatedStorageSettings.ApplicationSettings.TryGetValue(this.name, out this.value))
{
//not set yet
this.value = this.defaultValue;
IsolatedStorageSettings.ApplicationSettings[this.name] = this.value;
}
this.hasValue = true;
}
return this.value;
}
set
{
//save value to isolated storage
IsolatedStorageSettings.ApplicationSettings[this.name] = value;
this.value = value;
this.hasValue = true;
}
}
public T DefaultValue
{
get { return this.defaultValue; }
}
//clear cached value;
public void ForceRefresh()
{
this.hasValue = false;
}
}
Further development:
I receive this error on exiting the application:
A first chance exception of type 'System.IO.IsolatedStorage.IsolatedStorageException' occurred in mscorlib.dll
ERROR FOUND: I'm an idiot and left out one exclamation mark! from the trygetvalue part.
Could you please post your storage code so we could see exactly what's going on? In absense of that code, here's the code I use to save setting to local storage:
IsolatedStorageSettings isoStoreSettings = IsolatedStorageSettings.ApplicationSettings;
if (isoStoreSettings.Contains(key))
{
isoStoreSettings[key] = value;
}
else
{
isoStoreSettings.Add(key, value);
}
isoStoreSettings.Save();
My guess is that you're missing that last line that commits the changes to isolated storage settings to the materialized isolated store instead of just leaving them in memory. If that's not the case, please edit your post with the code so that we can help.

Resources