进程间通信-字符串的传递

近来写了个简单的音乐播放器, 每次双击音乐文件, 都会再次运行一个实例, 觉得不太方便, 只需一个运行着的实例即可, 因此着手解决这个问题.
    最常用的方法, 当然是在查找当前相同的进程名称, 如果有,则退出, 没有则初始化本实例. 方法比较简单,但有效.
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弄得那么多, 让人记也记不住, 查也不好查.

时间: 2024-08-29 23:51:12

进程间通信-字符串的传递的相关文章

规避字符串在传递过程中造成的编码问题

今天碰到一个让人脸绿的问题. 原来的做法是,如果页面出错,则往Cookie里塞错误信息,然后迁移到错误页面,再把错误信息从Cookie里取出来,显示到页面上. 这个做法原先都好好的,但是代码加密后,就出毛病了. 往Cookie里塞的时候还是好好的“无权限!”. 但是在错误页面取出来的时候就变成了乱码. 纠结了好久,终于想出一个解决方法,如下: 将错误信息搜集整理成一个类,然会出错的时候,Cookie里塞的不是字符串,而是错误代码. 迁移到错误页面后,根据错误代码前往错误信息类,取到错误信息显示到

C# 进程间通信之二传递复杂数据类型(转)

从C#下使用WM_COPYDATA传输数据说到Marshal的应用 笔者曾在一个项目的实施过程中,需要使用WM_COPYDATA在本地机器的两个进程间传输数据.在C++中实现非常简单,但在C#中实现时却出现了麻烦.由于没有指针,使用COPYDATASTRUCT结构传递数据时,无法正确传递lpData.从网上搜寻文档,找到一个例子,是将COPYDATASTRUCT结构的lpData声明为string.这样虽然能传递字符串,但不能传递随意的二进制数据. 偶然地,我查阅MSDN帮助时,发现了Marsh

Android进程间通信之----Aidl传递对象

转载请注明出处 CSDN废墟的树 前言 有关Android进程间通信之Aidl编程的基本使用步骤已经在上一篇博客中有讲解,Android studio 下的aidl编程实现Android的夸进程间通信.上一篇博客中只是演示了怎么利用Aidl实现跨进程间传递Java基本类型,以及Aidl传递Bitamap对象.可能在一些场景下你需要跨进程传递一个对象,那么Aidl是否能传递一个对象呢?答案是肯定的,网上也有很多相关的资料,之所以写这篇博客:一是当作自己学习笔记咯,二是把自己遇到的问题分享出来. A

windows 中如何将一个字符串信息传递给另一个线程而不是一个指针

http://www.veerchina.com/index.php?r=photoRequest/view&id=40689 http://www.veerchina.com/index.php?r=photoRequest/view&id=41746 http://www.veerchina.com/index.php?r=photoRequest/view&id=41686 http://www.veerchina.com/index.php?r=photoRequest/v

axios SpringMvc String[] 字符串数组传递

前端 import axios from 'axios' import qs from 'qs' axios.post("/getByUserIds", qs.stringify( {"userIds": userIds}, //userIds=["1","2","3"] {indices: false}) //该参数控制影响后台接收,参数传递格式(userIds=1&userIds=2&u

整数转换为字符串

因为64位下INT_MAX其长度不超过20,故此处将字符串数组传递进函数. int num2str(int num,char str[]) { char c; int i=0, j=0, k=0, tmp = num > 0 ? num : -1 * num; if (num > INT_MAX || num < INT_MIN) return -1; if (num<0) { str[i++] = '-'; ++j; num *= -1; //求余需要注意转换为正数,因为-111

Android第一行代码学习笔记六---Intent向活动传递数据

@1.向下一个活动传递数据: Intent提供了一系列putExtra()方法的重载,可以把我们想要传递的数据暂存在Intent中,启动了另一个活动后,只需把这些数据再从Intent中取出就可以了,比如firstActivity中有一个字符串要传递到secondActivity中,修改firstActivity中按钮点击事件,代码可以这样编写: button.setOnClickListener(new View.OnClickListener() { public void onClick(V

c#进程之间对象传递方法

1. 起源 KV项目下载底层重构升级决定采用独立进程进行Media下载处理,以能做到模块复用之目的,因此涉及到了独立进程间的数据传递问题. 目前进程间数据传递,多用WM_COPYDATA.共享dll.内存映射.Remoting等方式.相对来说,WM_COPYDATA方式更为简便,网上更到处是其使用方法. 而且Marshal这个静态类,其内置多种方法,可以很方便实现字符串.结构体等数据在不同进程间传递. 那么,对象呢?如何传递? 2.序列化 想到了,Newtonsoft.Json.dll这个神器.

C中字符串知识学习小记

1:在C中我们说"H"这是一个字符串,总共占有2个字节,后面有一个'\0'伪零结束符. 'H'这是一个数字.通过下面程序进行验证. #include <stdio.h> int main(void) { printf("%d %d\n",sizeof("c"),sizeof('s')); } 2:字符串创建过程 #include <stdio.h> int main(void) { char * p = "hel