技术开发 频道

基于Windows CE的Mutex简单探讨和应用

  【IT168 专稿】前些天,用VS.NET2008开发一个PDA的项目;这个PDA是基于Windows CE的操作系统;用户有个需求,当这个应用程序一旦开起来,如果他想再点击运行,就提醒他:该程序已经运行;于是本人就建议小兄弟用Mutex类实现,最后他告诉我不可以;用Mutex类去开发一般Windows 程式,会比较容易,但如果拿他去开发Windows CE的程式,就有些说词,本文就是基于这样的背景下展开的.

  Mutex单词是“互斥”的意思; 同性相斥,异性相吸(人类活动的多样性,早已打破这一铁定的规律,动物界应该还严格遵守这一约定…呵呵,题外话.);

  Mutex更详细的解释,就是mutual exclusion 对象的缩写;用一句计算机的行话来说,一个互斥体就是一个程序对象,它允许多个线程来共享相同的资源;例如对文件的访问,但并不允许同时访问;这在我们使用的过程中能体会到,比如你打开一个文件,你接着再打开一次的时候,它就提醒你,当前的应用程序已经打开,你是否继续等..;当一个程序运行起来的时候,这个互斥体就产生了,且带有唯一的名字;学过操作系统的,都会有这个概念叫互斥;上学的时候,老师举了个很好例子来说明,比如你在火车上,那个厕所就是很好的互斥体;你要用这个厕所,别人就不能用,直到别人使用完,你才能用,即使你闹肚子也不行,^-^..; 你打电话有时候也会遇到这种情况;如:该电话正在忙,请稍候再拨!

  闲话少说,那么在大家编程的时候,有时候用户有这样的需求,这个程序只要开启一次,如果有人想继续开启,就提醒他,这个应用程序正在运行;

  对Visual Studio.NET开发人员来讲,如果设计一个传统的Window Form程序好像就比较简单,用Mutex很容易解决这样的需求; 如下代码:

  [VB.NET]

  '引用Mutex的类

  
Imports System.Threading

  
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

  
'定义Mutex的类

  
Dim objMutex As Mutex

  
'得到应用程序的名称

  
Dim AppName As String = Assembly.GetExecutingAssembly().GetName().Name

  
'用这个应用程序的名字,去实例化这个Mutex

  objMutex
= New Mutex(False, AppName)

  
'判断是否有相同的应用程序在运行;

  
If objMutex.WaitOne(0, False) = False Then

  objMutex.Close()

  objMutex
= Nothing

  MessageBox.Show(
"这个程序正在运行!")

  ‘或者为了更通俗些,也可写成下面的代码;

  MessageBox.Show(
"该电话正在忙,请稍候再拨!")

  Close()
'关闭这个应用程序

  
Exit Sub

  
End If

  
End Sub

   这里强调下面的代码:

  objMutex = New Mutex(False, AppName)

   这里的AppName就很重要,如果你忽略这样的参数,你的上述的函数就失去了原有的意义;

  接下来,我们看看开发一个Windows CE的应用程序如何做;作为.NET Framework 的一个子集,.NET Compact Framework只提供了.NET Framework的一部分功能 ,所以特别的Mutex的对象的功能已经完全被弱化.; NET Compact Framework 并不支持这个所谓的互斥体,但幸运的是 Windows CE通过这个coredll.dll动态链接库中的几个函数可以实现这一功能; 有人就问啦,为什么是coredll.dll,而不是其他动态链接库呢?好问题,是因为Windows CE下大部分的API存在于coredll.dll里面,同时DllImport不仅仅支持Win32 API,他可以支持任何native 的DLL的引入。于是有人又要问啦,啥叫”native的DLL的引入?”..呵呵…自己查资料,网上一大堆..

  在操作系统创建这个Mutex是必须带有一个特别的命名,这个在文章开头已经讲的比较清楚,就是唯一的暂住证(哈哈..真的有点象..大家好好体会这个”暂住证”..);有了这个暂住证呢,这个Mutex的实际功能才能真正体现;如果你想再冒名创建同样的名字,对不起,系统就警告你;

  基本上来讲,如果你创建一个带特别命名的Mutex应用程序,就能确保这个应用程序能唯一地运行在操作系统中;

  作为.NET Framework 的一个子集,.NET Compact Framework只提供了.NET Framework的一部分功能,因此有时在实现一些功能时不得不借助于Windows CE API。另外还存在一些第三方的组件或资源,或以动态链接库形式提供,或者已经是COM组件。相对于.NET Compact Framework,它们都属于非托管资源。我们需要一种功能,实现由托管环境访问这些非托管资源。和.NET Framework 一样,平台调用P/Invoke(Platform Invocation Services)提供托管代码调用驻留于 DLL 中的非托管函数的功能。下面是一张平台调用的原理图(From MSDN)。

  .NET Compact Framework下,如何做平台调用呢?

  下面使用DllImport特征导入Windows CE的API函数MessageBoxW的定义。现举例说明:

Public class APIHelper
<DllImport("coredll.dll", SetLastError := true)> _
public static extern                      Private Shared function MessageBoxW(ByVal hWnd as IntPtr, ByVal text as String, ByVal caption as String caption, byVal type as uint) as Integer
End Function
End Class
然后可以对它进行调用;
Private sub button1_Click(ByVal sender as object, ByVal e as EventArgs )
  
Dim Zero as intPtr
APIHelper.MessageBoxW(Zero,
"测试MessageBoxW函数",
"API调用", 0)
End sub

   然后可以对它进行调用;

Private sub button1_Click(ByVal sender as object, ByVal e as EventArgs )
  
Dim Zero as intPtr
APIHelper.MessageBoxW(Zero,
"测试MessageBoxW函数",
"API调用", 0)
End sub

   可以看到,使用P/Invoke包括声明和调用两个过程,另外还有一个错误处理的过程。通过声明来指定要调用的非托管函数,.NET Compact Framework也是使用DllImport特性来进行声明,包括模块名、函数名及调用约定。与.NET Framework完整版的DllImport特性不同,.NET Compact Framework的一共包括五个公共字段:CallingConvention,CharSet,EntryPoint,PreserveSig和SetLastError。具体各字段的说明可以参考MSDN。

  有了上述的内容打底,我们就要用平台调用这样的概念来实现,Windows CE下,这个应用程序单独运行这样的用户需求;下面我创建了一个类,就叫SingleInstance Application;

Imports System
Imports System.Windows.Forms
‘记得要引用InteropServices这个类
Imports System.Runtime.InteropServices
Imports System.Reflection

Public Class SingleInstanceApplication
    
<DllImport("coredll.dll", SetLastError:=True)> _
    
Private Shared Function CreateMutex(ByVal Attr As IntPtr, ByVal Own As Boolean, ByVal Name As String) As Integer
    
End Function

    
<DllImport("coredll.dll", SetLastError:=True)> _
    
Private Shared Function ReleaseMutex(ByVal hMutex As IntPtr) As Boolean
    
End Function

    
Const ERROR_ALREADY_EXISTS As Long = 183

    
Public Sub Run(ByVal frm As Form)
        
Dim name As String = Assembly.GetExecutingAssembly().GetName().Name
        
Dim mutexHandle As IntPtr = CreateMutex(IntPtr.Zero, True, name)
        
Dim xError As Long = Marshal.GetLastWin32Error()

        
If xError <> ERROR_ALREADY_EXISTS Then
            Application.Run(frm)
        
Else
            
MsgBox("This Application already running now!")
            frm.Close()
        
End If
        ReleaseMutex(mutexHandle)
    
End Sub
End Class

   这个类导入了两个native 的函数,一个是创建Mutex,那另一个就是释放Mutex;还有一个简单的公用函数;

  这个Run 函数是创建一个带有应用程序名的Mutex,也顺便检查返回的错误代码,去看是否这个mutex已经存在;如果不错在呢,就让这个应用程序运行;

  最终会把这个Mutex释放掉;这样的写法是不是很简单,呵呵..

  如何引用这个类呢?下面是主程序的入口..

‘首先定义这个类 这是必须地。
Private oOneInstance As SingleInstanceApplication = Nothing

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ‘实例话这个类,这也是必须地.
        oOneInstance
= New SingleInstanceApplication()
‘ 调用这个类下面的主函数Run,这更是必须地.
        oOneInstance.Run(
Me)
End Sub

   上述代码全是关于VB.NET写的,有没有用C#写的呢,下面就是啦.

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

namespace Bitmatic
{
  
static class SingleInstanceApplication
  {
    [DllImport(
"coredll.dll", SetLastError = true)]
    
public static extern IntPtr CreateMutex(IntPtr Attr, bool Own, string Name);

    [DllImport(
"coredll.dll", SetLastError = true)]
    
public static extern bool ReleaseMutex(IntPtr hMutex);

    
const long ERROR_ALREADY_EXISTS = 183;

    
public static void Run(Form frm)
    {
      
string name = Assembly.GetExecutingAssembly().GetName().Name;
      IntPtr mutexHandle
= CreateMutex(IntPtr.Zero, true, name);
      
long error = Marshal.GetLastWin32Error();

      
if (error != ERROR_ALREADY_EXISTS)
        Application.Run(frm);

      ReleaseMutex(mutexHandle);
    }
  }
}

[MTAThread]
static void Main()
{
  SingleInstanceApplication.Run(
new Form1());
}

   上述代码在Windows CE(PDA),Windows XP下调试;开发工具是Visual Studio.Net 2008;

  最后是感言,非常感谢这么多的网友奉献他们的智慧,让我写这篇文章;更重要的是我在搜索的过程中,没有一篇完整的文章对在.NET Framework 和.NET Compact Framework对这个议题进行探讨;又近阶段有个项目要实现这样的用户需求,故总结归纳之,希大家共勉!

0
相关文章