1

WinFormsアプリがあります。すでに実行中のインスタンスがあり、ユーザーが別のインスタンスを起動しようとした場合、Application.Run()を呼び出す前にMutexと照合して停止します。その部分はうまく機能します。私がやりたいのは、新しいプロセスを強制終了する前に、アプリの新しいインスタンスから(文字列形式のデータとともに)既存のインスタンスにメッセージを渡すことです。

PostMessageを呼び出してみましたが、実行中のアプリでメッセージを受信しましたが、lparamで渡す文字列が失敗します(はい、最初に適切な文字列を渡していることを確認しました) 。どうすればこれを行うのが最善ですか?

static class Program
{
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern bool PostMessage(int hhwnd, uint msg, IntPtr wparam, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern uint RegisterWindowMessage(string lpString);

    private const int HWND_BROADCAST = 0xffff;
    static uint _wmJLPC = unchecked((uint)-1);

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        _wmJLPC = RegisterWindowMessage("JumpListProjectClicked");
        if (_wmJLPC == 0)
        {
            throw new Exception(string.Format("Error registering window message: \"{0}\"", Marshal.GetLastWin32Error().ToString()));
        }

        bool onlyInstance = false;
        Mutex mutex = new Mutex(true, "b73fd756-ac15-49c4-8a9a-45e1c2488599_ProjectTracker", out onlyInstance);

        if (!onlyInstance) {
            ProcessArguments();
            return;
        }

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());

        GC.KeepAlive(mutex);
    }

    internal static void ProcessArguments()
    {
        if (Environment.GetCommandLineArgs().Length > 1)
        {
            IntPtr param = Marshal.StringToHGlobalAuto(Environment.GetCommandLineArgs()[1]);
            PostMessage(HWND_BROADCAST, _wmJLPC, IntPtr.Zero, param);
        }
    }
}

他の場所では、私のフォームで...

protected override void WndProc(ref Message m)
{
    try
    {
        if (m.Msg == _wmJLPC)
        {
             // always returns an empty string
             string param = Marshal.PtrToStringAnsi(m.LParam);

             // UI code omitted
        }
    }
    catch (Exception ex)
    {
        HandleException(ex);
    }

    base.WndProc(ref m);
}
4

5 に答える 5

3

グレッグ、

StringToHGlobalAuto によって作成されたアンマネージ ポインターは、それを作成したプロセス空間でのみ有効です。それが参照するメモリは、他のプロセスからアクセスできません。

あるアプリから別のアプリにデータを渡すには、WM_COPYDATA メッセージで SendMessage() を使用します。

スコット

于 2009-07-31T21:54:43.003 に答える
0

これが簡単な方法です。私はコードを実行していませんが、あなたはアイデアを得る

class Program
{
    static Thread listenThread;
    static void Main(string[] args)
    {
        try
        {
            using (Mutex mutex = new Mutex(true, "my mutex"))
            {
                listenThread = new Thread(Listen);
                listenThread.IsBackground = true;
                listenThread.Start();
            }
        }
        catch (ApplicationException)
        {
            using (Mutex mutex = Mutex.OpenExisting("my mutex"))
            {
                mutex.WaitOne();
                try
                {
                    using (NamedPipeClientStream client = new NamedPipeClientStream("some pipe"))
                    {
                        using (StreamWriter writer = new StreamWriter(client))
                        {
                            writer.WriteLine("SomeMessage");
                        }
                    }
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
        }
    }
    static void Listen()
    {
        using (NamedPipeServerStream server = new NamedPipeServerStream("some pipe"))
        {
            using (StreamReader reader = new StreamReader(server))
            {
                for (; ; )
                {
                    server.WaitForConnection();
                    string message = reader.ReadLine();
                    //Dispatch the message, probably onto the thread your form 
                    //  was contructed on with Form.BeginInvoke

                }
            }
        }
    }
于 2009-07-31T20:57:06.177 に答える
0

コードをもう一度確認してください。StringToHGlobalAuto を使用して文字列を作成しています (Unicode で終わる可能性があります)。次に、Unicode を使用していない PtrToStringAnsi を呼び出しています。

このソリューションが機能しない場合は、いくつかのオプションがあります。それらについては、IPC (InterProcess Communication) を探すことで読むことができます。

私が使用した方法の 1 つは、必要なコンテンツを含むよく知られているファイルを作成することです。名前付きイベントでそのファイルの使用をロックし、別の名前付きイベントを設定してファイルが変更されたことを「所有者」アプリに伝えます。「所有者」はイベントをときどきチェックするか、ワーカー スレッドを起動してイベントを監視します。

繰り返しますが、IPC には多くの種類があります。これらのアイデアがうまくいかない場合は、探し続けてください。

于 2009-07-31T20:20:24.940 に答える
0

最近では、クロスプロセス通信を行うためのはるかに単純で最新の方法があります。特に、WCF を調べてください。

ほんの少しの学習曲線があることは認めますが。それを理解してしまえば、それは本当にとても簡単です。すべてをプログラムで行うこともできるため、構成の混乱について心配する必要はありません。

于 2009-07-31T20:33:11.297 に答える