zoukankan      html  css  js  c++  java
  • 进程间通信-字符串的传递

        近来写了个简单的音乐播放器, 每次双击音乐文件, 都会再次运行一个实例, 觉得不太方便, 只需一个运行着的实例即可, 因此着手解决这个问题.
        最常用的方法, 当然是在查找当前相同的进程名称, 如果有,则退出, 没有则初始化本实例. 方法比较简单,但有效.
    private static bool FoundRunningInstance()
    {
     Process currentProcess = Process.GetCurrentProcess();
     Process[] procList = Process.GetProcessesByName(currentProcess.ProcessName);

     foreach (Process proc in procList)
     {
      if (proc.Id != currentProcess.Id)
      {
       return true;
      }
     }
     return false;
    }

    public static void Main(string[] args)
    {
     if (args.Length == 0)
      Application.Run(new MainForm());
     if (args.Length == 1)
     {
      if (!FoundRunningInstance())
       Application.Run(new MainForm(args[0]));
      else
       Environment.Exit(0);
     }
    }
        这样运行起来是OK了, 但问题也随之而来, 如果已经运行了一个实例, 再双击一个音乐文件, 虽然不再运行新的实例, 但双击的音乐, 也没有预想的那样想起来. 后来想到微软的媒体播放器作为默认的播放器时, 每次双击新的音乐文件, 已经运行的实例会播放选定的音乐.
        如果实现这个效果呢?
        要让已经运行的实例接受新的音乐文件路径, 只有在双击后初始化新的实例前给running instance一个参数. 由此, 涉及到了进程间的通信. 实现进程间通信最常用的是使用windows API SendMessage函数. SendMessage函数的定义:
    private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
    在四个参数中,全是整型的, 但这里需要传送的是一个字符串. 使用SendMessage是无法直接传送字符串的, 但可以通过发送WM_COPYDATA消息, 发送自定义只读数据, 这个自定义的数据, 在C#中使用struct实现.
    public struct ProcessCopyDataStruct
    {
     public int dwData;  // 或许自己需要的四字节标识
     public int cbData;
     [MarshalAs(UnmanagedType.LPStr)]  // lpData字符串的长度
            public string lpData;  // 需要传送的字符串
    }
    到这里, SendMessage函数定义也需要重新改一下了.
    private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref ProcessCopyDataStruct lParam);
    Msg要传送的消息WM_COPYDATA的定义数值: public const int WM_COPYDATA = 0x004A;
        写到这里就要说说很多文章的不负责任了, 像WM_COPYDATA这类的变量, 虽说是API中使用, 可以查得到, 但对新手来说却是一头雾水, 把代码一套, 报错变量未定义, 就那么一个复制粘贴, 很多文章就是不把实际的值贴出来, 太不负责任了.
        定义好了结构, 就可以实现消息的发送了. 现在回头再修改一下FoundRunningInstance方法和Main方法.
        其中结构中dwData, 自己定义为:WM_QINGMUSIC = 0x8888;
    private static bool FoundRunningInstance(string musicFile)
    {
     Process currentProcess = Process.GetCurrentProcess();
     Process[] procList = Process.GetProcessesByName(currentProcess.ProcessName);

     foreach (Process proc in procList)
     {
      if (proc.Id != currentProcess.Id)
      {
       if (musicFile == null) return true;
       ProcessCopyDataStruct copydata;
       copydata.dwData = WM_QINGMUSIC;
       copydata.lpData = musicFile;
       copydata.cbData = System.Text.Encoding.Default.GetBytes(musicFile).Length + 1;
       SendMessage(proc.MainWindowHandle, WM_COPYDATA, currentProcess.Handle, ref copydata);
       return true;
      }
     }
     return false;
    }

    public static void Main(string[] args)
    {
     if (args.Length == 0)
     {
      if (!FoundRunningInstance(null))
       Application.Run(new MainForm());
      else
       Environment.Exit(0);
     }
     if (args.Length == 1)
     {
      if (!FoundRunningInstance(args[0]))
       Application.Run(new MainForm(args[0]));
      else
       Environment.Exit(0);
     }
    }
        到这里发送消息就做好了, 剩下的就是要Running Instance接收发过来的消息. 这里要重载一个方法WndProc.
    protected override void WndProc(ref Message m)
    {
     if (m.Msg == WM_COPYDATA)
     {
      ProcessCopyDataStruct copydata = (ProcessCopyDataStruct) m.GetLParam(typeof(ProcessCopyDataStruct));
      PlayMusic(copydata.lpData); // 此处为播放传过来的音乐文件路径, 可自由处理.
     }
     base.WndProc(ref m); // 这一句还是不能忘了.
    }
        进程间传送自定义结构数据, 就完成了. 其实本不复杂, 麻烦呢只能怪微软把个API弄得那么多, 让人记也记不住, 查也不好查.

  • 相关阅读:
    JeePlus:代码生成器
    JeePlus:API工具
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
  • 原文地址:https://www.cnblogs.com/fanyf/p/4499889.html
Copyright © 2011-2022 走看看