I am trying to open a sample project in the farseer with monogame in vs2017 but all the time I get this error:
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
///
private static void Main(string[] args)
{
using (FarseerPhysicsGame game = new FarseerPhysicsGame())
{
game.Run();
}
}
}
I created a Windows Forms application that uses a ChromiumBrowser. The application is composed by the follow components:
Main application
Web browser library
Launcher application
When I launch my application normally, the web browser works correctly. If I launch my application from a launcher, the web browser doesn't work. It tolds me the follow error:
Unhandled exception of 'System.IO.FileNotFoundException' in Unknown module.
Cannot load file or assembly 'CefSharp, Version=57.0.0.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138' or a relative dependency.
Unable to found the specified file.
I need to use the launcher not only for updates, but since the application is distributed on network, sometimes there are problems to access files on the server.
The problem is not relative only to my app. I created a test solution that I posted below and I have had the same issue.
Notes on the project
Cefsharp runtime is located in C:\Program Files (x86)\CEFRuntime\x64 and C:\Program Files (x86)\CEFRuntime\x86. (I created an installer that copy the runtime files in this position). Runtime is based on the NuGet package.
All executables are compiled in AnyCpu (AnyCpu support)
Cefsharp version 57 (Cef redist 3.2987.1601)
Runtime content
x64 folder
cef.pak
CefSharp.BrowserSubprocess.Core.dll
CefSharp.BrowserSubprocess.Core.pdb
CefSharp.BrowserSubprocess.exe
CefSharp.BrowserSubprocess.pdb
CefSharp.Core.dll
CefSharp.Core.pdb
CefSharp.Core.xml
CefSharp.dll
CefSharp.pdb
CefSharp.WinForms.dll
CefSharp.WinForms.pdb
CefSharp.WinForms.XML
CefSharp.XML
cef_100_percent.pak
cef_200_percent.pak
cef_extensions.pak
chrome_elf.dll
d3dcompiler_47.dll
devtools_resources.pak
icudtl.dat
libcef.dll
libEGL.dll
libGLESv2.dll
natives_blob.bin
snapshot_blob.bin
widevinecdmadapter.dll
locales folder (with all .paks)
x86 folder
cef.pak
CefSharp.BrowserSubprocess.Core.dll
CefSharp.BrowserSubprocess.Core.pdb
CefSharp.BrowserSubprocess.exe
CefSharp.BrowserSubprocess.pdb
CefSharp.Core.dll
CefSharp.Core.pdb
CefSharp.Core.xml
CefSharp.dll
CefSharp.pdb
CefSharp.WinForms.dll
CefSharp.WinForms.pdb
CefSharp.WinForms.XML
CefSharp.XML
cef_100_percent.pak
cef_200_percent.pak
cef_extensions.pak
chrome_elf.dll
d3dcompiler_47.dll
devtools_resources.pak
icudtl.dat
libcef.dll
libEGL.dll
libGLESv2.dll
natives_blob.bin
snapshot_blob.bin
widevinecdmadapter.dll
locales folder (with all .paks)
I post the test solution that gives me the same error.
Test Solution
The test solution is composed by three projects:
StackOverflowIssueLauncher
StackOverflowIssue (reference to WebBrowser)
WebBrowser (dll library that contains the webbrowser)
The code is shown below:
Project StackOverflowIssueLauncher
Program.cs
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace StackOverflowIssueLauncher {
/// <summary>
/// Launcher program
/// </summary>
internal static class Program {
/// <summary>
/// Launcher body
/// </summary>
[STAThread, LoaderOptimization(LoaderOptimization.MultiDomainHost)]
private static void Main() {
//Initialize path of application
string startupPath = Environment.CurrentDirectory;
string cachePath = Path.Combine(Path.GetTempPath(), "Program-" + Guid.NewGuid());
string assemblyPath = CanonicalizePathCombine(startupPath, #"..\..\..\StackOverflowIssue\bin\Debug\");
string executablePath = Path.Combine(assemblyPath, "StackOverflowIssue.exe");
string configFile = executablePath + ".config";
//Start App Domain
try {
var setup = new AppDomainSetup() {
ApplicationName = "StackOverflowIssue",
ShadowCopyFiles = "true",
ShadowCopyDirectories = assemblyPath,
CachePath = cachePath,
ConfigurationFile = configFile
};
var domain = AppDomain.CreateDomain("StackOverflowIssue", AppDomain.CurrentDomain.Evidence, setup);
domain.ExecuteAssembly(executablePath);
AppDomain.Unload(domain);
}
catch (Exception ex) {
MessageBox.Show(ex.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
//Empty cache path
try {
Directory.Delete(cachePath, true);
}
catch (Exception) {
//DO NOTHING
}
}
private static string CanonicalizePathCombine(string sourcePath, string destPath) {
string resultPath = Path.Combine(sourcePath, destPath);
var sb = new StringBuilder(Math.Max(260, 2 * resultPath.Length));
PathCanonicalize(sb, resultPath);
return sb.ToString();
}
[DllImport("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool PathCanonicalize([Out] StringBuilder sb, string src);
}
}
Project StackOverflowIssue
WebControlForm.cs
using System.Windows.Forms;
using WebBrowser;
namespace StackOverflowIssue {
/// <summary>
/// Form that contains the webbrowser control
/// </summary>
public class WebControlForm : Form {
/// <summary>
/// Create a new web control form
/// </summary>
public WebControlForm() {
InitializeComponent();
Controls.Add(new CefControl { Dock = DockStyle.Fill });
}
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.SuspendLayout();
//
// WebControlForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(529, 261);
this.Name = "WebControlForm";
this.Text = "WebControlForm";
this.ResumeLayout(false);
}
#endregion
}
}
MainForm.cs
using System;
using System.Windows.Forms;
namespace StackOverflowIssue {
/// <summary>
/// Main application form
/// </summary>
public partial class MainForm : Form {
/// <summary>
/// Creates the main form
/// </summary>
public MainForm() {
InitializeComponent();
}
/// <summary>
/// Show a new Web Control form
/// </summary>
/// <param name="sender">Object that raised the event</param>
/// <param name="e">Event arguments</param>
private void ShowBtn_Click(object sender, EventArgs e) {
var wcf = new WebControlForm();
wcf.Show(this);
}
/// <summary>
/// Variabile di progettazione necessaria.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Pulire le risorse in uso.
/// </summary>
/// <param name="disposing">ha valore true se le risorse gestite devono essere eliminate, false in caso contrario.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Codice generato da Progettazione Windows Form
/// <summary>
/// Metodo necessario per il supporto della finestra di progettazione. Non modificare
/// il contenuto del metodo con l'editor di codice.
/// </summary>
private void InitializeComponent() {
this.ShowBtn = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// ShowBtn
//
this.ShowBtn.Location = new System.Drawing.Point(12, 12);
this.ShowBtn.Name = "ShowBtn";
this.ShowBtn.Size = new System.Drawing.Size(134, 40);
this.ShowBtn.TabIndex = 0;
this.ShowBtn.Text = "Show web browser";
this.ShowBtn.UseVisualStyleBackColor = true;
this.ShowBtn.Click += new System.EventHandler(this.ShowBtn_Click);
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 261);
this.Controls.Add(this.ShowBtn);
this.Name = "MainForm";
this.Text = "Main form";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button ShowBtn;
}
}
Program.cs
using System;
using System.Diagnostics;
using System.Windows.Forms;
using WebBrowser;
namespace StackOverflowIssue {
/// <summary>
/// Main application program
/// </summary>
internal static class Program {
/// <summary>
/// Main application program.
/// </summary>
[STAThread] private static void Main() {
WebBrowserInitializer.Initialize();
Debug.Print("Application started");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
packages.config
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="cef.redist.x64" version="3.2987.1601" targetFramework="net452" />
<package id="cef.redist.x86" version="3.2987.1601" targetFramework="net452" />
<package id="CefSharp.Common" version="57.0.0" targetFramework="net452" />
<package id="CefSharp.WinForms" version="57.0.0" targetFramework="net452" />
</packages>
Project WebBrowser
CefControl.cs
using System.Windows.Forms;
using CefSharp.WinForms;
namespace WebBrowser {
/// <summary>
/// WebBrowser control
/// </summary>
public class CefControl: UserControl {
public CefControl() {
CefInitializer.Initialize();
InitializeComponent();
var cr = new ChromiumWebBrowser("https://www.google.com");
cr.Dock = DockStyle.Fill;
Controls.Add(cr);
}
/// <summary>
/// Variabile di progettazione necessaria.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Pulire le risorse in uso.
/// </summary>
/// <param name="disposing">ha valore true se le risorse gestite devono essere eliminate, false in caso contrario.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Codice generato da Progettazione componenti
/// <summary>
/// Metodo necessario per il supporto della finestra di progettazione. Non modificare
/// il contenuto del metodo con l'editor di codice.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
}
#endregion
}
}
CefInitializer.cs
using CefSharp;
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
namespace WebBrowser {
/// <summary>
/// Class that contains the base methods for CEF initializations
/// </summary>
public static class CefInitializer {
/// <summary>
/// Initialize properties
/// </summary>
static CefInitializer() {
CachePath = Path.Combine(Path.GetTempPath(), "SOIssue", "Cache");
LogFile = Path.Combine(Path.GetTempPath(), "SOIssue", "Logs");
UserDataPath = Path.Combine(Path.GetTempPath(), "SOIssue", "Data");
if (!Directory.Exists(CachePath))
Directory.CreateDirectory(CachePath);
if (!Directory.Exists(LogFile))
Directory.CreateDirectory(LogFile);
if (!Directory.Exists(UserDataPath))
Directory.CreateDirectory(UserDataPath);
//Complete the files combine
LogFile = Path.Combine(LogFile, "WebBrowser.log");
AppDomain.CurrentDomain.DomainUnload += (sender, args) => Shutdown();
}
/// <summary>
/// Shutdown all CEF instances
/// </summary>
internal static void Shutdown() {
using (var syncObj = new WindowsFormsSynchronizationContext()) {
syncObj.Send(o => {
if (Cef.IsInitialized)
Cef.Shutdown();
}, new object());
}
}
/// <summary>
/// Initialize CEF libraries
/// </summary>
[MethodImpl(MethodImplOptions.NoInlining)] internal static void Initialize() {
if (Cef.IsInitialized)
return;
//Get proxy properties
WebProxy proxy = WebRequest.DefaultWebProxy as WebProxy;
string cefPath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(Cef)).Location);
Debug.Print($"CEF Library Path: {cefPath}");
Debug.Assert(cefPath != null, nameof(cefPath) + " != null");
var settings = new CefSettings() {
BrowserSubprocessPath = Path.Combine(cefPath, "CefSharp.BrowserSubprocess.exe"),
LocalesDirPath = Path.Combine(cefPath, "locales"),
ResourcesDirPath = cefPath,
Locale = CultureInfo.CurrentCulture.Name,
CachePath = CachePath,
LogFile = LogFile,
UserDataPath = UserDataPath
};
if (proxy == null || proxy.Address.AbsoluteUri != string.Empty)
settings.CefCommandLineArgs.Add("no-proxy-server", string.Empty);
Cef.Initialize(settings);
}
internal static readonly string CachePath;
internal static readonly string LogFile;
internal static readonly string UserDataPath;
}
}
WebBrowserInitializer.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace WebBrowser {
/// <summary>
/// Class that contains the assembly resolve functions
/// </summary>
public static class WebBrowserInitializer {
private static readonly object _initializer = new object();
private static bool _initialized;
/// <summary>
/// Check if the WebBrowser is initialized
/// </summary>
public static bool IsInitialized {
get {
lock (_initializer)
return _initialized;
}
}
/// <summary>
/// Initialize the current assembly
/// </summary>
public static void Initialize() {
lock (_initializer) {
if (!_initialized) {
AppDomain.CurrentDomain.AssemblyResolve += CefSharp_AssemblyResolve;
_initialized = true;
}
}
}
/// <summary>
/// Try to resolve the assembly
/// </summary>
/// <param name="sender">Object that has raised the event</param>
/// <param name="args">Event raised</param>
/// <returns>Assembly loaded</returns>
private static Assembly CefSharp_AssemblyResolve(object sender, ResolveEventArgs args) {
Debug.Print($"Library: {args.Name}");
if (!args.Name.StartsWith("CefSharp", StringComparison.OrdinalIgnoreCase))
return null;
string assemblyName = args.Name.Split(new[] {','}, 2)[0] + ".dll";
foreach (var path in GetAssemblyPaths()) {
string checkPath = Path.Combine(path, assemblyName);
if (File.Exists(checkPath)) {
Debug.Print($"Relative path FOUND for {args.Name} in {checkPath}");
return Assembly.UnsafeLoadFrom(checkPath);
}
Debug.Write($"Relative path not found for {args.Name} in {checkPath}");
}
return null;
}
/// <summary>
/// Get all possible assembly paths
/// </summary>
/// <returns>List of possible assembly paths</returns>
private static IEnumerable<string> GetAssemblyPaths() {
string pathPrefix = Environment.Is64BitProcess ? "x64" : "x86";
if (Directory.Exists(#"C:\Program Files (x86)\CEFRuntime\" + pathPrefix))
yield return #"C:\Program Files (x86)\CEFRuntime\" + pathPrefix;
yield return Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, pathPrefix);
yield return Path.Combine(Environment.CurrentDirectory, pathPrefix);
Assembly currentAssembly = Assembly.GetAssembly(typeof(CefInitializer));
if (!string.IsNullOrEmpty(currentAssembly.Location))
yield return Path.Combine(currentAssembly.Location, pathPrefix);
}
}
}
packages.config
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="cef.redist.x64" version="3.2987.1601" targetFramework="net452" />
<package id="cef.redist.x86" version="3.2987.1601" targetFramework="net452" />
<package id="CefSharp.Common" version="57.0.0" targetFramework="net452" />
<package id="CefSharp.WinForms" version="57.0.0" targetFramework="net452" />
</packages>
Looking at CefSharp General Usage (https://github.com/cefsharp/CefSharp/wiki/General-Usage#need-to-knowlimitation), I noticed a line that explains that CefSharp works only on default AppDomain. I have looked at the project https://github.com/stever/AppHostCefSharp and I found a solution.
I need to run the WebBrowser on a Default AppDomain (I forked and edited RedGate.AppHost repository. See below for why i did it.). To allow communications between controls I implements two NamedPipes services, one on the main form, another on the created object.
I posted the complete solution (https://github.com/rupertsciamenna89/cefsharp-remoting) so the source code will be simplier to see. And it can be improved or fixed (like my english :))
I renamed the original projects to better names.
The solution is composed of 4 projects:
MainApplication [old StackOverflowIssue] (base application that I have to launch with ShadowCopy)
MainApplication.Launcher [old StackOverflowIssue.Launcher] (application launcher)
MainApplication.WebBrowser [old WebBrowser] (winforms controls library that contains the WebBrowser)
MainApplication.Interfaces (interfaces that must be implemented for the operations)
MainApplication.Interfaces
This project contains the interfaces that must be implemented by the client and the server. It contains five files:
IFormService is the interface that allows to create the control throught the RedGate.AppHost. It contains two Guids that identifies the unique names for Control/Server named pipes.
IAppClient is the client interface that will be implemented into the Control library to perform remote calls on the Application.
IAppServer is the server interface that will be implemented into the Application to accept remote calls from the Control library.
IWebBrowserClient is the client interface that will be implemented into Application to perform remote calls on the Control library.
IWebBrowserServer is the server interface that will be implemented into the Control libray to accept remote calls from the Application.
MainApplication.WebBrowser
This project implements the OutOfProcessEntryPoint interface that initializes the Control WCF Service. It contains the implementation of the Server interface and allows the remote client show the folder and retrieve the returned result.
MainApplication
I edited the Program.Main accepting the binaries path. I save this argument into a static variable that I'll use to crate the child process handle. The function that creates the process handle is this:
public static IChildProcessHandle CreateChildProcessHandle() {
string assemblyPath = _sourcePath ?? Path.GetDirectoryName(Assembly.GetAssembly(typeof(WebBrowserInitializer)).Location);
Debug.Assert(assemblyPath != null, "assemblyPath != null");
var al = new ChildProcessFactory() { ClientExecutablePath = _sourcePath };
return al.Create(Path.Combine(assemblyPath, "MainApplication.WebBrowser.dll"), false, Environment.Is64BitProcess);
}
If the source path isn't passed (like if I execute the application directly), RedGate will use the default location (the executing assembly path).
Once the windows is opened, the user could press the Show (or ShowDialog) button. The application "simply" run these lines of code:
//Generates client id and server id
string appId = Guid.NewGuid().ToString("N");
string controlId = Guid.NewGuid().ToString("N");
_service = AppServer.Start(appId, controlId);
_service.FormCompleted += Service_FormCompleted;
_locator = new FormServiceLocator(appId, controlId);
_element = _handle.CreateElement(_locator);
_service.StartRemoteClient();
_service.ShowDialog((long)Handle);
When the user will close the window, the callback function will be called:
private void Service_FormCompleted(object sender, AppServerEventArgs e) {
//Check if invoke is required
if (InvokeRequired) {
Invoke(new Action<object, AppServerEventArgs>(Service_FormCompleted), sender, e);
return;
}
_element = null;
MessageBox.Show(this, $"Result: {e.Result} - Data: {e.AdditionalData}");
}
MainApplication.Launcher
This is the project that launch our application with ShadowCopy enabled. I pass as argument the path of the binaries.
var domain = AppDomain.CreateDomain("CefSharp-Remoting",
AppDomain.CurrentDomain.Evidence, setup);
domain.ExecuteAssembly(executablePath, new[] { $"\"/path:{assemblyPath}\"" });
Why I forked the RedGate.AppHost repository
RedGate.AppHost try to found the Clients application looking into the Assembly location. With ShadowCopy enabled, this is not possible, because the application is copied into a "random" folder, and the Client application is in the source path.
I added the ClientExecutablePath property into the ChildProcessFactory.cs and ProcessStarter.cs, so the ProcessStarter use this folder instead of default folder if this property is setted.
You can see that edits in the follow files:
https://github.com/rupertsciamenna89/RedGate.AppHost/blob/master/RedGate.AppHost.Server/ChildProcessFactory.cs
https://github.com/rupertsciamenna89/RedGate.AppHost/blob/master/RedGate.AppHost.Server/ProcessStarter.cs
I've attempt to follow MSDN simple make a service instructions
Walkthrough: Creating a Windows Service Application in the Component Designer
https://msdn.microsoft.com/en-us/library/zt39148a(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
namespace WindowsService1
{
public partial class Service1 : ServiceBase
{
private System.ComponentModel.IContainer components;
private System.Diagnostics.EventLog eventLog1;
public Service1()
{
InitializeComponent();
eventLog1 = new System.Diagnostics.EventLog();
if (!System.Diagnostics.EventLog.SourceExists("MySource"))
{
System.Diagnostics.EventLog.CreateEventSource("MySource", "MyNewLog");
}
eventLog1.Source = "MySource";
eventLog1.Log = "MyNewLog";
}
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("In OnStart");
}
protected override void OnStop()
{
}
}
}
I seem to fail at the 2nd hurdle, "Adding Features to the Service"
When I compile I get Ambiguity between 'WindowsService1.Service1.eventLog1' and 'WindowsService1.Service1.Service1.eventLog1' and The type 'WindowsService1.Service1' already contains a defintion for 'components'
Thanks for the comments people got me looking in the right place, seems that you don't need to do step4 it is done automatically when you add the eventlog in the design view.
Service1.designer.cs looks like this
namespace WindowsService4
{
partial class Service1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.eventLog1 = new System.Diagnostics.EventLog();
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).BeginInit();
//
// Service1
//
this.ServiceName = "Service1";
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).EndInit();
}
#endregion
private System.Diagnostics.EventLog eventLog1;
}
}
I did everything from Example: What is the correct way to create a single-instance application? by Matt Davis.
However, I have an application to open files. I have this code:
static Mutex mutex = new Mutex(true, "{MyApplicationTest}");
[STAThread]
static void Main(string[] args)
{
if (mutex.WaitOne(TimeSpan.Zero, true))
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(args.Length == 0 ? new Form1(string.Empty) : new Form1(args[0]));
mutex.ReleaseMutex();
}
else
{
NativeMethods.PostMessage(
(IntPtr)NativeMethods.HWND_BROADCAST,
NativeMethods.WM_SHOWME,
IntPtr.Zero,
IntPtr.Zero);
}
How does open the next file in the case when the program is already running. The first file automatically opens. In contrast, the next click will only appearance of the application window on top of the screen.
Problem solved, thanks xxbbcc http://www.hanselman.com/blog/TheWeeklySourceCode31SingleInstanceWinFormsAndMicrosoftVisualBasicdll.aspx
using System;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices;
namespace SuperSingleInstance
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
string[] args = Environment.GetCommandLineArgs();
SingleInstanceController controller = new SingleInstanceController();
controller.Run(args);
}
}
public class SingleInstanceController : WindowsFormsApplicationBase
{
public SingleInstanceController()
{
IsSingleInstance = true;
StartupNextInstance += this_StartupNextInstance;
}
void this_StartupNextInstance(object sender, StartupNextInstanceEventArgs e)
{
Form1 form = MainForm as Form1; //My derived form type
form.LoadFile(e.CommandLine[1]);
}
protected override void OnCreateMainForm()
{
MainForm = new Form1();
}
}
}
Here is a Utility Class That I wrote a while back for a similar purpose.
(I guess the name GlobalMutexHelper is kind of redundant in this case, the name kind of stuck :)..anyways)
Since it implements IDisposable you can use it like so
using(var Mutexhelper=new GlobalMutexHelper("reasonably unique Name"))
{
//Code goes here
}
Its not necessary that this be implemented as an IDisposable but in my case I need it to be handy
as sometimes the "Single Instanceness" had to be dependent on other factors.
internal class GlobalMutexHelper : IDisposable
{
#region Constants and Fields
/// <summary>
/// The access rule.
/// </summary>
private readonly MutexAccessRule accessRule =
new MutexAccessRule(
new SecurityIdentifier(WellKnownSidType.WorldSid, null),
MutexRights.FullControl,
AccessControlType.Allow);
/// <summary>
/// The obj.
/// </summary>
private readonly Mutex obj;
/// <summary>
/// The sec settings.
/// </summary>
private readonly MutexSecurity secSettings = new MutexSecurity();
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="GlobalMutexHelper"/> class.
/// </summary>
/// <param name="mutexname">
/// The mutexname.
/// </param>
/// <exception cref="TimeoutException">
/// </exception>
/// <exception cref="Exception">
/// </exception>
public GlobalMutexHelper(string mutexname)
{
if (mutexname.Trim() != string.Empty)
{
this.secSettings.AddAccessRule(this.accessRule);
bool isNew;
this.obj = new Mutex(true, "Global\\SomeUniqueName_" + mutexname, out isNew);
this.obj.SetAccessControl(this.secSettings);
if (!isNew)
{
if (this.obj.WaitOne())
{
Console.WriteLine("Signalled");
}
else
{
throw new TimeoutException("Timedout while waiting for Mutex");
}
}
}
else
{
throw new Exception("The mutex name cannot be empty");
}
}
#endregion
#region Public Methods and Operators
/// <summary>
/// The dispose.
/// </summary>
public void Dispose()
{
this.obj.ReleaseMutex();
this.obj.Dispose();
}
#endregion
}
I have a class to hold session like this
public class SessionService : ISession
{
public HttpContext Context { get; set; }
public SessionService(HttpContext context)
{
this.Context = context;
}
}
I want to be able to inject the session object in various places in my MVC3 app.
I have this interface
interface ISession
{
HttpContext Context { get; set; }
}
I am using ninject to bind the session class to the interface like this
private void RegisterDependencyResolver()
{
var kernel = new StandardKernel();
kernel.Bind<ISession>().To<SessionService>();
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
My problem is how to pass the Httpcontext parameter into the SessionService constructor.
Any pointers most appreciated.
Thanks
Wherever you are setting up your dependencies:
kernel.Bind<HttpContext>().ToMethod(c => HttpContext.Current);
I have a bootstrapper class that does this with a RegisterServices method:
public static class NinjectMVC3
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule));
DynamicModuleUtility.RegisterModule(typeof(HttpApplicationInitializationModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<HttpContext>().ToMethod(c => HttpContext.Current);
}
}