最近在做文件关联,有一个问题可能比较棘手,就是选中多个文件打开的时候,Windows在关联的时候不是把这个所有的文件的路径传作为参数传给一个程序,而是每个路径关联一个程序,也就是会打开N个程序。显然,这个有些不是我们需要的。例如Mp3播放器,应该是选中N个音频文件后,只打开一个文件,并且这N个文件会建立成一个播放列表。
那么简单的记录下,我们这里碰见的问题:
1 程序只能被打开一次,或者说只会有一个有效的程序在运行。这里,我们可以利用CreateMutex来实现互斥,利用GetLastError来判断是否存在。
2 接受参数:这个参数在Main函数的参数里面。很好理解。
3:选中N个文件只打开一个程序:这个肯定是利用到程序之间的通讯,当然肯定还有其他的办法,只是我不知道而已。这里我们就用WM_COPYDATA这个消息来实现。在c#中,我们实现两个函数,贴出代码,这样就会简化我们的程序:
public struct COPYDATASTRUCT
{
/// <summary>
/// 用户自定义数据
/// </summary>
public int dwData;
/// <summary>
/// 数据长度
/// </summary>
public int cbData;
/// <summary>
/// 数据地址指针
/// </summary>
public IntPtr lpData;
}
[DllImport("Coredll.dll", EntryPoint = "SendMessage", SetLastError = true)]
public static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
public static void ReceivCopyData(ref Message m, out int dwData, out byte[] lpdata)
{
Console.WriteLine("ReceivCopyData********");
COPYDATASTRUCT cds = new COPYDATASTRUCT();
cds = (COPYDATASTRUCT)(Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT)));
dwData = cds.dwData;
int len = cds.cbData;
lpdata = new byte[len];
Marshal.Copy(cds.lpData, lpdata, 0, len);
m.Result = (IntPtr)0;
}
public static int SendCopyData(IntPtr hWnd, int dwData, byte [] lpdata)
{
#region
Console.WriteLine("SendCopyData ********");
COPYDATASTRUCT cds = new COPYDATASTRUCT();
cds.dwData = dwData;
cds.cbData = lpdata.Length;
cds.lpData = Marshal.AllocHGlobal(lpdata.Length);
Marshal.Copy(lpdata, 0, cds.lpData, lpdata.Length);
IntPtr lParam = Marshal.AllocHGlobal(Marshal.SizeOf(cds));
Marshal.StructureToPtr(cds, lParam, false);
int result = 0;
try
{
result = RockApi.SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, lParam);
}
finally
{
Marshal.FreeHGlobal(cds.lpData);
// Marshal.DestroyStructure(lParam, typeof(COPYDATASTRUCT));
Marshal.FreeHGlobal(lParam);
}
return result;
#endregion
}
关于string 和byte[]之间的转换,可以有很多的方法,最好用的就是:
string --->>> byte []
byte[] lpdata = System.Text.Encoding.Default.GetBytes(args[0]);
byte [] --->>> string
string str = System.Text.Encoding.Default.GetString(lpData, 0, lpData.Length);
希望我说的清楚。
这里有一个比较棘手的问题就是WindowCE 下的C# (compact net ) Form本身没有消息机制,我们只能利用MessageWindow来实现,这样我们有碰见一个问题,就是我们在发送WM_COPYDATA消息的时候只能使用SendMessage,而不能是PostMessage.
这个如果多个程序之间没有协调好,就会容易有问题,所以我们可以利用COPYDATASTRUCT 这个结构体重的dwData来判断。你发的值,你肯定也是知道的撒。
还有一个问题就是我们在实际用的时候发现基本上我们选中N(N>1)个的时候,只能打开N-1个,配置打印信息,我们可以发现这个是因为第二个打开的时候其实第一个的消息接受还没有好。所以第二个里面我们采用延时一下Sleep,这样就可以的了。
代码就是主要的上面,写的一个例子,也是贴在下面:就是最基本的代码:
int handle= RockApi.CreateMutex(IntPtr.Zero, true, "MP3Player");
if (RockApi.GetLastError() == RockApi.ERROR_ALREADY_EXISTS)//当前有进程
{
Console.WriteLine(" ERROR_ALREADY_EXISTS ");
System.Threading.Thread.Sleep(100);
if (args.Length != 0)
{
Console.WriteLine("Main Send CopyData _____");
byte[] lpdata = System.Text.Encoding.Default.GetBytes(args[0]);
RockApi.SendCopyData(new IntPtr(0xFFFF), 0, lpdata);
return;
}
return;
}
else
{
Console.WriteLine("CreateMutex First ");
Form1 form = new Form1();
if (args.Length != 0)
form.filepath = args[0];
Application.Run(form);
RockApi.CloseHandle(handle);
}
完毕:
Rocky