IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Avatar
jt.e
Člen
Avatar
jt.e:23.2.2016 20:44

Zdravím.
Jak se prosím v C# odchytává pokus uživatele otevřít soubor v aplikaci (WinForm)?

 
Odpovědět
23.2.2016 20:44
Avatar
jt.e
Člen
Avatar
jt.e:23.2.2016 20:58

jedná se mi o otevření, když už aplikace běží (ne přes argument)

Editováno 23.2.2016 20:59
 
Nahoru Odpovědět
23.2.2016 20:58
Avatar
jt.e
Člen
Avatar
jt.e:23.2.2016 21:24

Ještě raději dodám, že mám takto bráním spuštění další instance aplikace:

static class Program
{

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    ///
    static Mutex mutex = new Mutex(false, "Prohlížeč 3.0");

    [STAThread]
    static void Main()
    {
        if (!mutex.WaitOne(TimeSpan.FromSeconds(2), false))
        {
            return;
        }

        try
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
        finally
        {
            mutex.ReleaseMutex();
        }
    }
}
 
Nahoru Odpovědět
23.2.2016 21:24
Avatar
Michal Žůrek - misaz:23.2.2016 21:36

nijak, prostě se spustí ta přiřazená aplikace (popř tu co vybere uživatel v dialogu Otevřít v aplikaci), tak že ti ten soubor předají v parametrech příkazového řádku no a takto nově spuštěná aplikace si to nějak vykomunikuje s již otevřenou aplikací.

 
Nahoru Odpovědět
23.2.2016 21:36
Avatar
Michal Žůrek - misaz:23.2.2016 21:37

i když nevím jestli ti to nějak půjde tím že ti to zablokuje ten mutex, ale snad jo.

 
Nahoru Odpovědět
23.2.2016 21:37
Avatar
jt.e
Člen
Avatar
Odpovídá na Michal Žůrek - misaz
jt.e:23.2.2016 21:52

Chápu, ale jak ty parametry předat spuštěné aplikaci?

 
Nahoru Odpovědět
23.2.2016 21:52
Avatar
Odpovídá na jt.e
Michal Žůrek - misaz:23.2.2016 22:05

operační systém ti předá jako parametr příkazového řádku cestu k souboru na který uživatel poklikal.

 
Nahoru Odpovědět
23.2.2016 22:05
Avatar
jt.e
Člen
Avatar
jt.e:23.2.2016 22:11

To chápu. Ale ne když poklepeš na soubor, tak se ti spustí další instance aplikace, když ta zjistí, že už běží jiná, tak jí musí ty své parametry nějak předat a poté se sama ukončit.

 
Nahoru Odpovědět
23.2.2016 22:11
Avatar
jt.e
Člen
Avatar
jt.e:24.2.2016 20:09

Nějak mi to funguje
Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace textshow
{
    static class Program
    {
        public const int WM_COPYDATA = 0x004A;
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);

        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        ///
        [STAThread]
        static void Main()
        {
            IntPtr h = FindWindowByCaption(IntPtr.Zero, "Prohlížeč 3.0");
            if (IntPtr.Zero == h)
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
            else
            {
                String[] arguments = Environment.GetCommandLineArgs();
                if (arguments.Length > 1)
                {
                    SendParam(h, arguments[1]);
                }
            }
        }

        public static IntPtr IntPtrAlloc<T>(T param)
        {
            IntPtr retval = Marshal.AllocHGlobal(Marshal.SizeOf(param));
            Marshal.StructureToPtr(param, retval, false);
            return retval;
        }

        // Free a pointer to an arbitrary structure from the global heap.
        public static void IntPtrFree(ref IntPtr preAllocated)
        {
            if (IntPtr.Zero == preAllocated)throw (new NullReferenceException("Zero == preAllocated"));
            Marshal.FreeHGlobal(preAllocated);
            preAllocated = IntPtr.Zero;
        }

        public static void SendParam(IntPtr hWnd, string message)
        {
            try
            {
                COPYDATASTRUCT cds;
                cds.dwData = IntPtr.Zero;
                cds.cbData = 2 * (message.Length + 1); // TADY NEVÍM
                cds.lpData = Marshal.StringToHGlobalAuto(message.ToString());
                IntPtr cdsBuffer = IntPtrAlloc(cds);
                SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, cdsBuffer);
                IntPtrFree(ref cds.lpData);
                IntPtrFree(ref cdsBuffer);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}
ve Form1.cs
protected override void WndProc(ref Message m)
{
    if(m.Msg == Program.WM_COPYDATA)
    {
        try
        {
            COPYDATASTRUCT cds;
            cds = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT));
            string arg = Marshal.PtrToStringAuto(cds.lpData);

            LoadFromFile(arg);
        }
        catch (Exception ex)
        {
            textBox1.Text = ex.Message;
        }
    }

    base.WndProc(ref m);
}

Je pořád nemůžu přijít nato jak správně zaznamenat velikost objektu:
cds.cbData = 2 * (message.Length + 1); myslím nebude úplně správně
a můžete mi prosím říct co ještě mám nesprávně?

Editováno 24.2.2016 20:12
 
Nahoru Odpovědět
24.2.2016 20:09
Avatar
jt.e
Člen
Avatar
jt.e:24.2.2016 20:21

Oprava: Jen pořád nemůžu přijít na to, jak správně zaznamenat..

A prosím, kdyby mi někdo vysvětlil funkce IntPtrAlloc a IntPtrFree, ty mám z netu a moc nechápu co přesně dělají (Je mi pouze jasné že slouží k alokaci a uvolnění), ale jak přesně fungují a proč tam musí být...?

Editováno 24.2.2016 20:23
 
Nahoru Odpovědět
24.2.2016 20:21
Avatar
jt.e
Člen
Avatar
jt.e:24.2.2016 22:18

Takže asi hotovo.

//Program.cs

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace textshow
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        ///
        [STAThread]
        static void Main()
        {
            IntPtr h = Native.FindWindowByCaption(IntPtr.Zero, "Prohlížeč 3.0");
            if (IntPtr.Zero == h)
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
            else
            {
                String[] arguments = Environment.GetCommandLineArgs();
                if (arguments.Length > 1)
                {
                    SendParam(h, arguments[1]);
                }
            }
        }

        public static void SendParam(IntPtr hWnd, string message)
        {
            try
            {
                COPYDATASTRUCT cds;
                cds.dwData = 2016;
                cds.cbData = 0;
                cds.lpData = message;

                IntPtr strprt = Marshal.AllocHGlobal(Marshal.SizeOf(cds)); ;
                Marshal.StructureToPtr(cds, strprt, false);
                Native.SendMessage(hWnd, Native.WM_COPYDATA, IntPtr.Zero, strprt);
                Native.IntPtrFree(ref strprt);
                Native.SetForegroundWindow(hWnd);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }

    //-------------------------------------------------------------------------
    public struct COPYDATASTRUCT
    {
        public int cbData;
        public int dwData;
        [MarshalAs(UnmanagedType.LPStr)]
        public string lpData;
    }
    //-------------------------------------------------------------------------
    public static class Native
    {
        public const int WM_COPYDATA = 0x004A;

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);

        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        public static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);

        [DllImport("user32.dll")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

        public static void IntPtrFree(ref IntPtr preAllocated)
        {
            if (IntPtr.Zero == preAllocated) return;

            Marshal.FreeHGlobal(preAllocated);
            preAllocated = IntPtr.Zero;
        }
    }
    //-------------------------------------------------------------------------
}
//============================================
//Form1.cs

using System;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;

namespace textshow
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public void LoadFromFile(string filename)
        {
            try
            {
                using (StreamReader r = new StreamReader(filename, Encoding.Default, true))
                {
                    textBox1.Clear();
                    textBox1.Text = r.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public void LoadParams()
        {
            String[] arguments = Environment.GetCommandLineArgs();
            if (arguments.Length > 1)
            {
                if (File.Exists(arguments[1])) LoadFromFile(arguments[1]);
            }
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            LoadParams();
        }

        protected override void WndProc(ref Message m)
        {
            if(m.Msg == Native.WM_COPYDATA)
            {
                try
                {
                    COPYDATASTRUCT cds;
                    cds = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT));
                    if (cds.dwData == 2016)
                    {
                        LoadFromFile(cds.lpData);
                    }
                }
                catch (Exception ex)
                {
                    textBox1.Text = ex.Message;
                }
            }

            base.WndProc(ref m);
        }
    }
}
Akceptované řešení
+5 Zkušeností
Řešení problému
 
Nahoru Odpovědět
24.2.2016 22:18
Avatar
jt.e
Člen
Avatar
jt.e:25.2.2016 19:10

jen kdyby to někdo potřeboval, tak ještě doporučím změnit data struktury pro podporu unicode cest k souborům:

public struct COPYDATASTRUCT
    {
        public int cbData;
        public int dwData;
        [MarshalAs(UnmanagedType.LPWStr)] ///<-
        public string lpData;
    }
 
Nahoru Odpovědět
25.2.2016 19:10
Avatar
Odpovídá na jt.e
sadlomaslox25:25.2.2016 20:27

podle me to mas nejaky slozity. ja bych osobne pouzij asi jen

[STAThread]
static void Main(string[] args)
{
    try
    {
        NamedPipeServerStream server = new NamedPipeServerStream("myServer") ;
        Task.Factory.StartNew(() =>
        {
            var stream = new StreamReader(server);
            while (true)
            {
                server.WaitForConnection();
                var filePath = stream.ReadLine();
                server.Disconnect();
                MessageBox.Show($"File: {filePath}", "Title", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
            }
        });
    }
    catch (Exception ex)
    {
        using (var client = new NamedPipeClientStream("myServer"))
        using (var stream = new StreamWriter(client))
        {
            client.Connect(3000);
            stream.AutoFlush = true;
            stream.WriteLine(args?.FirstOrDefault() ?? "none");
        }
        return;
    }
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}
 
Nahoru Odpovědět
25.2.2016 20:27
Avatar
jt.e
Člen
Avatar
Odpovídá na sadlomaslox25
jt.e:25.2.2016 21:51

A jak v tomto způsobu předám spuštěné aplikaci argumenty a spustím funkci LoadFromFile ? Mohl bych prosit o ukázku na daném projektu?

Editováno 25.2.2016 21:53
 
Nahoru Odpovědět
25.2.2016 21:51
Avatar
jt.e
Člen
Avatar
jt.e:25.2.2016 21:55

http://leteckaposta.cz/711220678

Editováno 25.2.2016 21:58
 
Nahoru Odpovědět
25.2.2016 21:55
Avatar
Odpovídá na jt.e
sadlomaslox25:25.2.2016 23:19
public partial class Form1 : Form
    {
        public Form1(string filename)
        {
            InitializeComponent();
            LoadFromFile(filename);
        }

        public void LoadFromFile(string filename)
        {
            if (!File.Exists(filename))
            {
                textBox1.Clear();
                MessageBox.Show("File not exists");
                return;
            }
            try
            {
                using (StreamReader r = new StreamReader(filename, Encoding.Default, true))
                {
                    textBox1.Clear();
                    textBox1.Text = r.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    ///
    [STAThread]
    static void Main(string[] args)
    {
        Form1 form = null;
        try
        {
            NamedPipeServerStream server = new NamedPipeServerStream("myServer");
            Task.Factory.StartNew(() =>
            {
                var stream = new StreamReader(server);
                while (true)
                {
                    server.WaitForConnection();
                    var filePath = stream.ReadLine();
                    server.Disconnect();
                    form.Invoke(new Action(() => form.LoadFromFile(filePath)));
                }
            });
        }
        catch (Exception ex)
        {
            using (var client = new NamedPipeClientStream("myServer"))
            using (var stream = new StreamWriter(client))
            {
                client.Connect(3000);
                stream.AutoFlush = true;
                stream.WriteLine(args?.FirstOrDefault() ?? "");
            }
            return;
        }
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(form = new Form1(args?.FirstOrDefault()));
    }
}
 
Nahoru Odpovědět
25.2.2016 23:19
Avatar
jt.e
Člen
Avatar
jt.e:26.2.2016 19:49

Díky moc. Sám bych to dohromady nedal, .Pipe, Invoke, FirstOrDefault jsou pro mě nové věci.

 
Nahoru Odpovědět
26.2.2016 19:49
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 18 zpráv z 18.