Open file in current instance of my program?

Example:

If you opened and started Visual Studio (2010), and then double-click the misc * .cs file on the desktop of your PC, the file will open in the currently running instance of Visual Studio instead of opening another instance of VS.

How can I get my own C # program to simulate this behavior?

In other words, if I have a file type, such as * .myfile, associated with my program, and the user double-clicks * .myfile in Windows Explorer and .... my program is already running ..... it should open the file without Windows starting another instance of my program. If the program was not started, Windows can start the instance normally.

Please note that multiple instances of my program are allowed - the same as Visual Studio.

Any suggestions would be appreciated!

+5
source share
3 answers

If you look at what is registered for the .cs file in the registry, you will see that this is not Visual Studio. For express edition, for example. the registered application is "VCSExpress.exe", and the studio runs in "WDExpress.exe". In advanced versions, I think the studio works like "devenv.exe". An interesting point is that there are two applications: your user interface application and a kind of launch application. I do not know how VS does this, but I could imagine it: the launcher interacts with the user interface through any kind of interprocess communication, for example. named pipes. (see here) Perhaps try the following:

  • The Launcher application (your file extension is registered on it) is trying to open a channel for the UI application as a client.
  • If this fails, it starts a new instance of the UI application and passes the file name as a parameter. Named Pipe Application Launch User Interface
  • If the pipe is opened successfully, that is, the UI instance is already running, the launcher sends the file name to the existing user interface process through the channel.
  • Launcher exits after completing a task in the UI
+3
source

Almost 20 years have passed since I should have done something like this, but IIRC, you are doing something like this:

  • First of all, create a Mailslot (or any other convenient IPC tool)
  • If you are asked to open a document of the type that should go to an existing instance, and if there are no other Mailslots messages, you continue on
  • If there is Mailslot, you send Mailslot an open message with information about the file, and then exit.
  • Enter the code to reply to open Mailslot messages.

If you take steps before creating windows, they should act the way you want.

0
source

I created some template project that implements this material using Windows messaging. The template is huge and contains some other things (such as localization, updates, formatting, clipboard and interface for documents, so actions in MDI can be easily redirected to MDI children). If you want to view the template, try this link (or this link )

Some of the code:

Win32.cs:

public partial class Win32 { //public const int WM_CLOSE = 16; //public const int BN_CLICKED = 245; public const int WM_COPYDATA = 0x004A; public struct CopyDataStruct : IDisposable { public IntPtr dwData; public int cbData; public IntPtr lpData; public void Dispose() { if (this.lpData != IntPtr.Zero) { LocalFree(this.lpData); this.lpData = IntPtr.Zero; } } } [DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref CopyDataStruct lParam); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr LocalAlloc(int flag, int size); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr LocalFree(IntPtr p); } 

Program.cs:

 static class Program { static Mutex mutex = new Mutex(true, guid()); static string guid() { // http://stackoverflow.com/questions/502303/how-do-i-programmatically-get-the-guid-of-an-application-in-net2-0 Assembly assembly = Assembly.GetExecutingAssembly(); var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0]; return attribute.Value; } static int MainWindowHandle { get { return Settings.Default.hwnd; } set { Settings sett = Settings.Default; sett.hwnd = value; sett.Save(); } } public static string GetFileName() { ActivationArguments a = AppDomain.CurrentDomain.SetupInformation.ActivationArguments; // aangeklikt bestand achterhalen string[] args = a == null ? null : a.ActivationData; return args == null ? "" : args[0]; } [STAThread] static void Main() { if (mutex.WaitOne(TimeSpan.Zero, true)) { #region standaard Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); #endregion #region Culture instellen string cult = CultureInfo.CurrentCulture.Name; Thread.CurrentThread.CurrentUICulture = new CultureInfo(cult); Thread.CurrentThread.CurrentCulture = new CultureInfo(cult); #endregion MainForm frm = new MainForm(); MainWindowHandle = (int)frm.Handle; Application.Run(frm); MainWindowHandle = 0; mutex.ReleaseMutex(); } else { int hwnd = 0; while (hwnd == 0) { Thread.Sleep(600); hwnd = MainWindowHandle; } if (hwnd != 0) { Win32.CopyDataStruct cds = new Win32.CopyDataStruct(); try { string data = GetFileName(); cds.cbData = (data.Length + 1) * 2; // number of bytes cds.lpData = Win32.LocalAlloc(0x40, cds.cbData); // known local-pointer in RAM Marshal.Copy(data.ToCharArray(), 0, cds.lpData, data.Length); // Copy data to preserved local-pointer cds.dwData = (IntPtr)1; Win32.SendMessage((IntPtr)hwnd, Win32.WM_COPYDATA, IntPtr.Zero, ref cds); } finally { cds.Dispose(); } } } } } 

MainFrom.cs:

 [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] protected override void WndProc(ref Message m) { switch (m.Msg) { case Win32.WM_COPYDATA: Win32.CopyDataStruct st = (Win32.CopyDataStruct)Marshal.PtrToStructure(m.LParam, typeof(Win32.CopyDataStruct)); string strData = Marshal.PtrToStringUni(st.lpData); OpenFile(strData); Activate(); break; default: // let the base class deal with it base.WndProc(ref m); break; } } 

It works even when running up to 15 files at a time.

0
source

Source: https://habr.com/ru/post/1206911/


All Articles