我这边写了一个程序 AA.exe 该程序用来处理,图片的压缩的问题。有这样的场景 D:\images 下有很多用户不断传来大的图片,AA.exe来处理这些图片,可能不能马上处理,于是想到用消息队列来排队用AA.exe来处理.问写怎样的程序?用C#来做.谢谢!!!

解决方案 »

  1.   

    因为自己没有做过,只能给你找到下面的资源,可以看看
    Microsoft近期推出一种用于生成集成应用程序的新平台——Microsoft 
    .NET框架。.NET 框架允许开发人员使用任何编程语言迅速生成和部署Web 
    服务和应用程序。Microsoft Intermediate Language (MSIL)和实时 
    (JIT )编译器使这种不依赖语言的框架得以实现。   与.NET框架同时面世的还有一种新的编程语言C#(读“C sharp”)。 
    C#是一种简单、新颖、面向对象和类型安全的编程语言。利用 .NET 框架 
    和 C# (除 Microsoft? Visual Basic ?和 Managed C++之外),用户 
    可以编写功能强大的 Microsoft Windows?和 Web应用程序及服务。本文 
    提供了这样的一个解决方案,它的重点是 .NET 框架和 C# 而不是编程语 
    言。C#语言的介绍可以在“ C# 简介和概述(英文)”找到。   近期的文章“MSMQ:可伸缩、高可用性的负载平衡解决方案(英文)” 
    介绍了一种解决方案,用于高可用性消息队列(MSMQ)的可伸缩负载平衡 
    解决方案体系结构。此解决方案中涉及了一种将 Windows服务用作智能消 
    息路由器的开发方案。这样的解决方案以前只有 Microsoft Visual C++ 
    程序员才能实现,而 .NET 框架的出现改变了这种情况。从下面的解决方 
    案中,您可以看到这一点。 .NET 框架应用程序   这里介绍的解决方案是一种用来处理若干消息队列的 Windows服务; 
    其中每个队列都是由多个线程进行处理(接收和处理消息)。处理程序使 
    用循环法技术或应用程序特定值(消息 AppSpecific属性)从目的队列列 
    表中路由消息,并使用消息属性来调用组件方法。(示例进程也属于这种 
    情况。)在后一种情况下,组件的要求是它能够实现给定的接口IWeb 
    Message要处理错误,应用程序需要将不能处理的消息发送到错误队列中。   消息应用程序的结构与以前的活动模板库(ATL )应用程序相似,它 
    们之间的主要不同在于用于管理服务的代码的封装和 .NET 框架组件的使 
    用。要创建Windows服务,.NET框架用户仅仅需要创建一个从 ServiceBase 
    (来自System.ServiceControl程序集)继承的类。这毫不奇怪,因为.NET 
    框架是面向对象的。 应用程序结构   应用程序中主要的类是 ServiceControl ,它是从 ServiceBase继承 
    的。因而,它必须实现 OnStart和 OnStop 方法,以及可选的 OnPause和 
    OnContinue方法。事实上,类是在静态方法 Main 内构造的: using System; 
    using System.ServiceProcess; public class ServiceControl: ServiceBase 

      // 创建服务对象的主入口点 
      public static void Main() 
      { 
       ServiceBase.Run(new ServiceControl()); 
      }   // 定义服务参数的构造对象 
      public ServiceControl() 
      { 
       CanPauseAndContinue = true; 
       ServiceName = "MSDNMessageService"; 
       AutoLog = false; 
      }   protected override void OnStart(string[] args) {...} 
      protected override void OnStop() {...} 
      protected override void OnPause() {...} 
      protected override void OnContinue() {...} 
    }   ServiceControl类创建一系列 CWorker对象,即,为需要处理的每个 
    消息队列创建 CWorker类的一个实例。根据定义中处理队列所需的线程数 
    目,CWorker 类依次创建了一系列的 CWorkerThread对象。CWorkerThread 
    类创建的一个处理线程将执行实际的服务工作。   使用 CWorker和 CWorkerThread类的主要目的是确认服务控件 Start、 
    Stop、Pause 和 Continue 命令。因为这些进程必须是无阻塞的,命令操 
    作最终将在后台处理线程上执行。   CWorkerThread 是一个抽象类,被 CWorkerThreadAppSpecific 、 
    CWorkerThreadRoundRobin 和 CWorkerThreadAssembly继承。这些类以不 
    同的方式处理消息。前两个类通过给另一队列发送消息来处理消息(其不 
    同之处在于确定接收队列路径的方式),最后一个类则使用消息属性来调 
    用组件方法。   .NET 框架内部的错误处理是以基类 Exception为基础的。当系统引 
    发或捕获错误时,这些错误必须是从 Exception中导出的类。CWorker 
    ThreadException 类就是这样一种实现,它通过附加额外属性(用于定义 
    服务是否应继续运行)来扩展基类。   最后,应用程序包含两种结构。这些值类型定义了辅助进程或线程的 
    运行时参数,以简化 CWorker和 CWorkerThread对象的结构。使用值类型 
    结构(而不是引用类型类)能够确保这些运行时参数维护的是数值(而不 
    是引用)。 IWebMessage 接口   CWorkerThread 的实现之一是一个调用组件方法的类。这个名为 
    CWorkerThreadAssembly 的类使用 IWebMessage接口来定义服务和组件之 
    间的约定。   与当前版本的 Microsoft Visual Studio?不同,C#接口可以在任何 
    语言中显式定义,而不需要创建和编译 IDL文件。C# IWebMessage接口的 
    定义如下: 
    public interface IWebMessage 

      WebMessageReturn Process(string sMessageLabel, string sMessage 
      Body, int iAppSpecific); 
      void Release(); 
    } ATL 代码中的 Process 方法是为处理消息而指定的。Process 方法的返 
    回代码定义为枚举类型 WebMessageReturn: public enum WebMessageReturn 

      ReturnGood, 
      ReturnBad, 
      ReturnAbort 
    }   枚举的定义如下:Good表示继续处理,Bad 表示将消息写入错误队列, 
    Abort 表示终止处理。Release 方法为服务提供了轻松清除类实例的途径。 
    因为仅在垃圾回收的过程中才调用类实例的析构函数,所以确保所有占用 
    昂贵资源(例如数据库连接)的类都有一个能够在析构之前被调用的方法, 
    用来释放这些资源,这是一种非常好的构思。 名称空间   在这里先简单介绍一下名称空间。名称空间允许在内部和外部表示中 
    将应用程序组织成为逻辑元素。服务内的所有代码都包含在 MSDNMessage 
    Service.Service 名称空间内。尽管服务代码包含在若干文件中,但是由 
    于它们包含在同一名称空间中,因此用户不需要引用其他文件。   由于 IWebMessage接口包含在 MSDNMessageService.Interface 名称 
    空间中,因此使用此接口的线程类具有一个接口名称空间。 服务类   应用程序的目的是监视和处理消息队列,每一队列在收到消息时都执 
    行不同的进程。应用程序是作为 Windows服务来实现的。 ServiceBase 类   如前所述,服务的基本结构是从 ServiceBase继承的类。重要的方法 
    包括 OnStart、OnStop、OnPause 和 OnContinue ,每一个替代方法都与 
    一个服务控制操作直接对应。OnStart 方法的目的是创建 CWorker对象, 
    而 CWorker类又创建 CWorkerThread对象,然后在该对象中创建执行服务 
    工作的线程。   服务的运行时配置(以及 CWorker和 CWorkerThread对象的属性)是 
    在基于 XML的配置文件中维护的。它的名称与创建的 .exe 文件相同,但 
    带有一个 .cfg 后缀。配置示例如下: 
    〈?xml version="1.0"?〉 
    〈configuration〉 
    〈ProcessList〉 
     〈ProcessDefinition 
        ProcessName="Worker1" 
        ProcessDesc="Message Worker with 2 Threads" 
        ProcessType="AppSpecific" 
        ProcessThreads="2" 
        InputQueue=".\private$\test_load1" 
        ErrorQueue=".\private$\test_error"〉 
      〈OutputList〉 
       〈OutputDefinition OutputName=".\private$\test_out11" /〉 
       〈OutputDefinition OutputName=".\private$\test_out12" /〉 
      〈/OutputList〉 
     〈/ProcessDefinition〉 
     〈ProcessDefinition 
        ProcessName="Worker2" 
        ProcessDesc="Assembly Worker with 1 Thread" 
        ProcessType="Assembly" 
        ProcessThreads="1" 
        InputQueue=".\private$\test_load2" 
        ErrorQueue=".\private$\test_error"〉 
      〈OutputList〉 
       〈OutputDefinition OutputName="C:\MSDNMessageService\Message 
       Example.dll" /〉 
       〈OutputDefinition OutputName="MSDNMessageService.Message 
       Sample.ExampleClass"/〉 
      〈/OutputList〉 
     〈/ProcessDefinition〉 
    〈/ProcessList〉 
    〈/configuration〉   对此信息的访问通过来自 System.Configuration 程序集的 Config 
    Manager 类来管理。静态 Get方法返回信息的集合,这些集合将被枚举以 
    获得单个属性。这些属性集的设置决定了辅助对象的运行时特征。除了这 
    一配置文件,您还应该创建定义 XML文件结构的图元文件,并在其中引用 
    位于服务器 machine.cfg配置文件中的图元文件: 〈?xml version ="1.0"?〉 
    〈MetaData xmlns="x-schema:CatMeta.xms"〉 
      〈DatabaseMeta InternalName="MessageService"〉 
      〈ServerWiring Interceptor="Core_XMLInterceptor"/〉 
      〈Collection 
         InternalName="Process" PublicName="ProcessList" 
         PublicRowName="ProcessDefinition" 
         SchemaGeneratorFlags="EMITXMLSCHEMA"〉 
       〈Property InternalName="ProcessName" Type="String" Meta 
       Flags="PRIMARYKEY" /〉 
       〈Property InternalName="ProcessDesc" Type="String" /〉 
       〈Property InternalName="ProcessType" Type="Int32" Default 
       Value="RoundRobin" 〉 
         〈Enum InternalName="RoundRobin" Value="0"/〉 
         〈Enum InternalName="AppSpecific" Value="1"/〉 
         〈Enum InternalName="Assembly" Value="2"/〉 
       〈/Property〉 
       〈Property InternalName="ProcessThreads" Type="Int32" 
       DefaultValue="1" /〉 
       〈Property InternalName="InputQueue" Type="String" /〉 
       〈Property InternalName="ErrorQueue" Type="String" /〉 
       〈Property InternalName="OutputName" Type="String" /〉 
       〈QueryMeta InternalName="All" MetaFlags="ALL" /〉 
       〈QueryMeta InternalName="QueryByFile" CellName="__FILE" 
       Operator="EQUAL" /〉 
      〈/Collection〉 
      〈Collection 
         InternalName="Output" PublicName="OutputList" 
         PublicRowName="OutputDefinition" 
         SchemaGeneratorFlags="EMITXMLSCHEMA"〉 
       〈Property InternalName="ProcessName" Type="String" Meta 
       Flags="PRIMARYKEY" /〉 
       〈Property InternalName="OutputName" Type="String" Meta 
       Flags="PRIMARYKEY" /〉 
       〈QueryMeta InternalName="All" MetaFlags="ALL" /〉 
       〈QueryMeta InternalName="QueryByFile" CellName="__FILE" 
       Operator="EQUAL" /〉 
      〈/Collection〉 
      〈/DatabaseMeta〉 
      〈RelationMeta   
       PrimaryTable="Process" PrimaryColumns="ProcessName" 
       ForeignTable="Output" ForeignColumns="ProcessName" 
       MetaFlags="USECONTAINMENT"/〉 
    〈/MetaData〉  
      

  2.   

      由于 Service类必须维护一个已创建辅助对象的列表,因此使用了 
    Hashtable 集合,用于保持类型对象的名称/ 数值对列表。Hashtable 不 
    仅支持枚举,还允许通过关键字来查询值。在应用程序中,XML 进程名称 
    是唯一的关键字: 
    private Hashtable htWorkers = new Hashtable(); 
    IConfigCollection cWorkers = ConfigManager.Get("ProcessList", new 
    AppDomainSelector()); 
    foreach (IConfigItem ciWorker in cWorkers) 

      WorkerFormatter sfWorker = new WorkerFormatter(); 
      sfWorker.ProcessName = (string)ciWorker["ProcessName"]; 
      sfWorker.ProcessDesc = (string)ciWorker["ProcessDesc"]; 
      sfWorker.NumberThreads = (int)ciWorker["ProcessThreads"]; 
      sfWorker.InputQueue = (string)ciWorker["InputQueue"]; 
      sfWorker.ErrorQueue = (string)ciWorker["ErrorQueue"]; 
      // 计算并定义进程类型 
      switch ((int)ciWorker["ProcessType"]) 
      { 
       case 0: 
         sfWorker.ProcessType = WorkerFormatter.SFProcessType. 
         ProcessRoundRobin; 
         break; 
       case 1: 
         sfWorker.ProcessType = WorkerFormatter.SFProcessType. 
         ProcessAppSpecific; 
         break; 
       case 2: 
         sfWorker.ProcessType = WorkerFormatter.SFProcessType. 
         ProcessAssembly; 
         break; 
       default: 
         throw new Exception("Unknown Processing Type"); 
      } 
     
     // 执行更多的工作以读取输出信息 
      string sProcessName = (string)ciWorker["ProcessName"]; 
      if (htWorkers.ContainsKey(sProcessName)) 
       throw new ArgumentException("Process Name Must be Unique: " 
       + sProcessName); 
      htWorkers.Add(sProcessName, new CWorker(sfWorker)); 
    }   在这段代码中没有包含的主要信息是输出数据的获取。每一个进程定 
    义中都有一组相应的输出定义项。该信息是通过如下的简单查询读取的: string sQuery = "SELECT * FROM OutputList WHERE ProcessName=" + 
      sfWorker.ProcessName + " AND Selector=appdomain://"; 
    ConfigQuery qQuery = new ConfigQuery(sQuery); 
    IConfigCollection cOutputs = ConfigManager.Get("OutputList", 
    qQuery); 
    int iSize = cOutputs.Count, iLoop = 0; 
    sfWorker.OutputName = new string[iSize]; 
    foreach (IConfigItem ciOutput in cOutputs) 
      sfWorker.OutputName[iLoop++] = (string)ciOutput["OutputName"];   CWorkerThread 和 Cworker类都有相应的服务控制方法,根据服务控 
    制操作进行调用。由于 Hashtable中引用了每一个 CWorker对象,因此需 
    要枚举 Hashtable的内容,以调用适当的服务控制方法: 
    foreach (CWorker cWorker in htWorkers.Values) 
      cWorker.Start();   类似地,实现的 OnPause、OnContinue和 OnStop 方法是通过调用 
    CWorker 对象上的相应方法来执行操作的。 CWorker 类   CWorker 类的主要功能是创建和管理 CWorkerThread对象。Start 、 
    Stop、Pause 和 Continue 方法调用相应的 CWorkerThread方法。实际的 
    CWorkerThread 对象是在Start 方法中创建的。与使用 Hashtable管理辅 
    助对象引用的 Service类相似,CWorker 使用 ArrayList(简单的动态数 
    组)来维护线程对象的列表。   C#消息队列应用程序(2)
    未知作者
    aspsky.net
    2001-3-6 21:25:42  在这个数组内部,CWorker 类创建了 CWorkerThread类的一个实现版本。CWorkerThread 类(将在下面讨论)是一个必须继承的抽象类。导出类定义了消息的处理方式: 
    aThreads = new ArrayList(); 
    for (int idx=0; idx〈sfWorker.NumberThreads; idx++) 

      WorkerThreadFormatter wfThread = new WorkerThreadFormatter(); 
      wfThread.ProcessName = sfWorker.ProcessName; 
      wfThread.ProcessDesc = sfWorker.ProcessDesc; 
      wfThread.ThreadNumber = idx; 
      wfThread.InputQueue = sfWorker.InputQueue; 
      wfThread.ErrorQueue = sfWorker.ErrorQueue; 
      wfThread.OutputName = sfWorker.OutputName; 
      // 定义辅助类型,并将其插入辅助线程结构 
      CWorkerThread wtBase; 
      switch (sfWorker.ProcessType) 
      { 
       case WorkerFormatter.SFProcessType.ProcessRoundRobin: 
         wtBase = new CWorkerThreadRoundRobin(this, wfThread); 
         break; 
       case WorkerFormatter.SFProcessType.ProcessAppSpecific: 
         wtBase = new CWorkerThreadAppSpecific(this, wfThread); 
         break; 
       case WorkerFormatter.SFProcessType.ProcessAssembly: 
         wtBase = new CWorkerThreadAssembly(this, wfThread); 
         break; 
       default: 
         throw new Exception("Unknown Processing Type"); 
      } 
      // 添加对数组的调用 
      aThreads.Insert(idx, wtBase); 
    }   一旦所有的对象都已创建,就可以通过调用每个线程对象的 Start方法来启动它们: 
    foreach(CWorkerThread cThread in aThreads) 
      cThread.Start();   Stop、Pause 和 Continue 方法在 foreach循环里执行的操作类似。Stop方法具有如下的垃圾收集操作: 
    GC.SuppressFinalize(this);   在类析构函数中将调用 Stop 方法,这样,在没有显式调用 Stop 方法的情况下也可以正确地终止对象。如果调用了 Stop 方法,将不需要析构函数。SuppressFinalize方法能够防止调用对象的 Finalize 方法(析构函数的实际实现)。 CWorkerThread 抽象类   CWorkerThread 是一个由 CWorkerThreadAppSpecifc、CWorkerThread、RoundRobin 和 CWorkerThreadAssembly继承的抽象类。无论如何处理消息,队列的大部分处理是相同的,所以 CWorkerThread类提供了这一功能。这个类提供了抽象方法(必须被实际方法替代)以管理资源和处理消息。   类的工作再一次通过 Start、Stop、Pause 和 Continue 方法来实现。在 Start方法中引用了输入和错误队列。在 .NET 框架中,消息由 System.Messaging 名称空间处理: 
    // 尝试打开队列,并设置默认的读写属性 
    MessageQueue mqInput = new MessageQueue(sInputQueue); 
    mqInput.MessageReadPropertyFilter.Body = true; 
    mqInput.MessageReadPropertyFilter.AppSpecific = true; 
    MessageQueue mqError = new MessageQueue(sErrorQueue); 
    // 如果使用 MSMQ COM,则将格式化程序设置为 ActiveX 
    mqInput.Formatter = new ActiveXMessageFormatter(); 
    mqError.Formatter = new ActiveXMessageFormatter();   一旦定义了消息队列引用,即会创建一个线程用于实际的处理函数(称为 ProcessMessages)。在 .NET 框架中,使用 System.Threading名称空间很容易实现线程处理: 
    procMessage = new Thread(new ThreadStart(ProcessMessages)); 
    procMessage.Start();   ProcessMessages 函数是基于 Boolean值的处理循环。当数值设为False,处理循环将终止。因此,线程对象的 Stop 方法只设置这一Boolean值,然后关闭打开的消息队列,并加入带有主线程的线程: 
    // 加入服务线程和处理线程 
    bRun = false; 
    procMessage.Join(); 
    // 关闭打开的消息队列 
    mqInput.Close(); 
    mqError.Close(); Pause 方法只设置一个 Boolean 值,使处理线程休眠半秒钟: if (bPause) 
      Thread.Sleep(500);   最后,每一个 Start、Stop、Pause 和 Continue 方法将调用抽象的OnStart 、OnStop、OnPause 和 OnContinue 方法。这些抽象方法为实现的类提供了挂钩,以捕获和释放所需的资源。   ProcessMessages 循环具有如下基本结构: 
    ●接收Message。 
    ●如果Message具有成功的Receive,则调用抽象ProcessMessage方法。 
    ●如果Receive或ProcessMessage失败,将Message发送至错误队列中。 Message mInput; 
    try 

      

  3.   

      // 从队列中读取,并等候 1 秒 
      mInput = mqInput.Receive(new TimeSpan(0,0,0,1)); 

    catch (MessageQueueException mqe) 

      // 将消息设置为 null 
      mInput = null; 
      // 查看错误代码,了解是否超时 
      if (mqe.ErrorCode != (-1072824293) ) //0xC00E001B 
      { 
       // 如果未超时,发出一个错误并记录错误号 
       LogError("Error: " + mqe.Message); 
       throw mqe; 
      } 

    if (mInput != null) 

      // 得到一个要处理的消息,调用处理消息抽象方法 
      try 
      { 
       ProcessMessage(mInput); 
      } 
      // 捕获已知异常状态的错误 
      catch (CWorkerThreadException ex) 
      { 
       ProcessError(mInput, ex.Terminate); 
      } 
      // 捕获未知异常,并调用 Terminate 
      catch 
      { 
       ProcessError(mInput, true); 
      } 
    }   ProcessError方法将错误的消息发送至错误队列。另外,它也可能引发异常来终止线程。如果ProcessMessage方法引发了终止错误或 CWorkerThreadException类型,它将执行此操作。 CworkerThread 导出类   任何从 CWorkerThread中继承的类都必须提供 OnStart、OnStop、OnPause、OnContinue和 ProcessMessage 方法。OnStart 和 OnStop方法获取并释放处理资源。OnPause 和 OnContinue 方法允许临时释放和重新获取这些资源。ProcessMessage方法应该处理消息,并在出现失败事件时引发 CWorkerThreadException 异常。   由于 CWorkerThread构造函数定义运行时参数,导出类必须调用基类构造函数: 
    public CWorkerThreadDerived(CWorker v_cParent, WorkerThread 
    Formatter v_wfThread) 
      : base (v_cParent, v_wfThread) {}   导出类提供了两种类型的处理:将消息发送至另一队列,或者调用组件方法。接收和发送消息的两种实现使用了循环技术或应用程序偏移(保留在消息 AppSpecific属性中),作为使用哪一队列的决定因素。此方案中的配置文件应该包括队列路径的列表。实现的 OnStart和 OnStop 方法
    应该打开和关闭对这些队列的引用: 
    iQueues = wfThread.OutputName.Length; 
    mqOutput = new MessageQueue[iQueues]; 
    for (int idx=0; idx〈iQueues; idx++) 

      mqOutput[idx] = new MessageQueue(wfThread.OutputName[idx]); 
      mqOutput[idx].Formatter = new ActiveXMessageFormatter(); 
    }   在这些方案中,消息的处理很简单:将消息发送必要的输出队列。在循环情况下,这个进程为: 
    try 

      mqOutput[iNextQueue].Send(v_mInput); 

    catch (Exception ex) 

      // 如果错误强制终止异常 
      throw new CWorkerThreadException(ex.Message, true); 

    // 计算下一个队列号 
    iNextQueue++; 
    iNextQueue %= iQueues;   后一种调用带消息参数的组件的实现方法比较有趣。ProcessMessage方法使用 IWebMessage接口调入一个 .NET 组件。OnStart 和 OnStop 方法获取和释放此组件的引用。   此方案中的配置文件应该包含两个项目:完整的类名和类所在文件的位置。按照 IWebMessage接口中的定义,在组件上调用 Process方法。   要获取对象引用,需要使用 Activator.CreateInstance 方法。此函数需要一个程序集类型。在这里,它是从程序集文件路径和类名中导出的。 
    一旦获取对象引用,它将被放入合适的接口: 
    private IWebMessage iwmSample; 
    private string sFilePath, sTypeName; 
    // 保存程序集路径和类型名称 
    sFilePath = wfThread.OutputName[0]; 
    sTypeName = wfThread.OutputName[1]; 
    // 获取对必要对象的引用 
    Assembly asmSample = Assembly.LoadFrom(sFilePath); 
    Type typSample = asmSample.GetType(sTypeName); 
    object objSample = Activator.CreateInstance(typSample); 
    // 定义给对象的必要接口 
    iwmSample = (IWebMessage)objSample;   获取对象引用后,ProcessMessage方法将在 IWebMessage接口上调用Process 方法: 
    WebMessageReturn wbrSample; 
    try 

      // 定义方法调用的参数 
      string sLabel = v_mInput.Label; 
      string sBody = (string)v_mInput.Body; 
      int iAppSpecific = v_mInput.AppSpecific; 
      // 调用方法并捕捉返回代码 
      wbrSample = iwmSample.Process(sLabel, sBody, iAppSpecific); 

    catch (InvalidCastException ex) 

      // 如果在消息内容中发生错误,则强制发出一个非终止异常 
      throw new CWorkerThreadException(ex.Message, false); 

    catch (Exception ex) 

      // 如果错误调用程序集,则强制发出终止异常 
      throw new CWorkerThreadException(ex.Message, true); 

    // 如果没有错误,则检查对象调用的返回状态 
    switch (wbrSample) 

      case WebMessageReturn.ReturnBad: 
       throw new CWorkerThreadException 
         ("Unable to process message: Message ed bad", false); 
      case WebMessageReturn.ReturnAbort: 
       throw new CWorkerThreadException 
         ("Unable to process message: Process terminating", true); 
      default: 
       break; 
    }   提供的示例组件将消息正文写入数据库表。如果捕获到严重数据库错误,您可能希望终止处理过程,但是在这里,仅仅将消息标记为错误的消息。   由于此示例中创建的类实例可能会获取并保留昂贵的数据库资源,所以用 OnPause和 OnContinue 方法释放和重新获取对象引用。 检测设备   就象在所有优秀的应用程序中一样,检测设备用于监测应用程序的状态。NET 框架大大简化了将事件日志、性能计数器和 Windows管理检测设备(WMI )纳入应用程序的过程。消息应用程序使用时间日志和性能计数器,二者都是来自 System.Diagnostics 程序集。   在 ServiceBase类中,您可以自动启用事件日志。另外,ServiceBaseEventLog成员支持写入应用程序事件日志: 
    EventLog.WriteEntry(sMyMessage, EventLogEntryType.Information);   对于写入事件日志而不是应用程序日志的应用程序,它能够很容易地创建和获取 EventLog 资源的引用(正如在 CWorker类中所做的一样),并能够使用 WriteEntry 方法记录日志项: 
    private EventLog cLog; 
    string sSource = ServiceControl.ServiceControlName; 
    string sLog = "Application"; 
    // 查看源是否存在,如果不存在,则创建源 
    if (!EventLog.SourceExists(sSource)) 
      EventLog.CreateEventSource(sSource, sLog); 
    // 创建日志对象,并引用现在定义的源 
    cLog = new EventLog(); 
    cLog.Source = sSource; 
    // 在日志中写入条目,表明创建成功 
    cLog.WriteEntry("已成功创建", EventLogEntryType.Information);   .NET 框架大大简化了性能计数器。对于每一个处理线程、线程导出的用户和整个应用程序,这一消息应用程序都能提供计数器,用于跟踪消息数量和每秒钟处理消息的数量。要提供此功能,您需要定义性能计数器的类别,然后增加相应的计数器实例。   性能计数器的类别在服务 OnStart方法中定义。这些类别代表两种计数器——消息总数和每秒钟处理的消息数: 
    CounterCreationData[] cdMessage = new CounterCreationData[2]; 
    cdMessage[0] = new CounterCreationData("Messages/Total", "Total 
    Messages Processed", 
    PerformanceCounterType.NumberOfItems64); 
    cdMessage[1] = new CounterCreationData("Messages/Second", 
    "Messages Processed a Second", 
    PerformanceCounterType.RateOfChangePerSecond32); 
    PerformanceCounterCategory.Create("MSDN Message Service", "MSDN 
    Message Service Counters", cdMessage);   一旦定义了性能计数器类别,将创建 PerformanceCounter 对象以访问计数器实例功能。PerformanceCounter对象需要类别、计数器名称和一个可选的实例名称。对于辅助进程,将使用来自 XML文件的进程名称,代码如下: 
    pcMsgTotWorker = new PerformanceCounter("MSDN Message Service", 
    "Messages/Total", sProcessName); 
    pcMsgSecWorker = new PerformanceCounter("MSDN Message Service", 
    "Messages/Second", sProcessName); 
    pcMsgTotWorker.RawValue = 0; 
    pcMsgSecWorker.RawValue = 0; 要增加计数器的值,仅仅需要调用适当的方法: pcMsgTotWorker.IncrementBy(1); 
    pcMsgSecWorker.IncrementBy(1); 最后说明一点,服务终止时,安装的性能计数器类别应该从系统中删除: PerformanceCounterCategory.Delete("MSDN Message Service");   由于性能计数器在 .NET 框架中工作,因此需要运行一项特殊的服务。此服务(PerfCounterService)提供了共享内存。计数器信息将写入共享内存,并被性能计数器系统读取。 安装   在结束以前,我们来简要介绍一下安装以及称为 installutil.exe的安装工具。由于此应用程序是 Windows服务,它必须使用installutil.exe来安装。因此,需要使用一个从 System.Configuration.Install 程序集中继承的 Installer类: 
    public class ServiceRegister: Installer 

      private ServiceInstaller serviceInstaller; 
      private ServiceProcessInstaller processInstaller; 
      public ServiceRegister() 
      { 
       // 创建服务安装程序 
       serviceInstaller = new ServiceInstaller(); 
       serviceInstaller.StartType = ServiceStart.Manual; 
       serviceInstaller.ServiceName = ServiceControl.ServiceControl 
       Name; 
       serviceInstaller.DisplayName = ServiceControl.ServiceControl 
       Desc; 
       Installers.Add(serviceInstaller); 
       // 创建进程安装程序 
       processInstaller = new ServiceProcessInstaller(); 
       processInstaller.RunUnderSystemAccount = true; 
       Installers.Add(processInstaller); 
      } 
    }   如此示例类所示,对于一个 Windows服务,服务和服务进程各需要一个安装程序,以定义运行服务的帐户。其他安装程序允许注册事件日志和性能计数器等资源。 总结   从这个 .NET 框架应用程序示例中可以看出,以前只有 Visual C++程序员能够编写的应用程序,现在使用简单的面向对象程序即可实现。尽管我们的重点是 C# ,但本文所述的内容也同样适用于 Visual Basic 和Managed C++.新的 .NET 框架使开发人员能够使用任何编程语言来创建功能强大、可伸缩的 Windows应用程序和服务。   新的 .NET 框架不仅简化和扩展了编程的种种可能,还能够轻松地将人们经常遗忘的应用程序检测设备(例如性能监测计数器和事件日志通知)合并到应用程序中。尽管这里的应用程序没有使用 Windows管理检测设备(WMI ),但 .NET 框架同样也可以应用它。 
      

  4.   

    LIST,HASHTABLE,QUEUE 等等不都是的么,主线程监视队列和运行线程数,然后处理啊....