zoukankan      html  css  js  c++  java
  • 利用共享内存映射实现程序只能启动一次的限制

    //=============================================================================
    //
    // 描述: 程序单次运行检测单元
    // 作者: sgao
    // 日期: 2015-09-25
    // 备注: 程序创建的句柄都会在进程结束后自动释放,所以这里没有做关闭句柄操作
    //
    //=============================================================================
    
    unit uRunOnceChecker;
    
    interface
    uses
      SysUtils,Windows;
    
    type
      //共享内存信息
      TShareInfo = record
        AppHandle : THandle;
      end;
      PShareInfo = ^TShareInfo;
    
      //检查程序是否运行,如未运行创建共享内存
      //参数1:程序标识
      //参数2:共享内存信息(外部创建,内部释放)
      //返回值:程序是否已经运行
      function CheckOrCreate(AGuidId : string; var AShareInfo : PShareInfo) : Boolean;
    
      //检查程序是否已运行
      //参数1:程序标识
      //参数2:共享内存信息
      //返回值:程序是否已经运行
      function Check(AGuidId : string; out AShareInfo : PShareInfo) : Boolean;
    
    
    
    
    implementation
    
      //检查程序是否运行,如未运行创建共享内存
      //参数1:程序标识
      //参数2:共享内存信息(外部创建,内部释放)
      //返回值:程序是否已经运行
      function CheckOrCreate(AGuidId : string; var AShareInfo : PShareInfo) : Boolean;
      var
        hMapFile : THandle;
        pInfo : PShareInfo;
      begin
        Result := False;
        if AShareInfo = nil then
          raise Exception.Create('需传入共享内存信息');
    
        //检查共享内存是否已经创建
        hMapFile := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, PChar(AGuidId));
        //如果共享内存尚未创建
        if hMapFile = 0 then
        begin
          //创建内存映像文件--该句柄在程序退出时释放
          hMapFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(TShareInfo), PChar(AGuidId));
          //映射内存
          pInfo := MapViewOfFile(hMapFile, FILE_MAP_WRITE or FILE_MAP_READ, 0, 0, 0);
          //初始化内存
          pInfo^.AppHandle := AShareInfo.AppHandle;
          Dispose(AShareInfo);
          AShareInfo := pInfo;
        end
        //共享内存已经创建
        else
        begin
          Dispose(AShareInfo);
          pInfo := MapViewOfFile(hMapFile, FILE_MAP_WRITE or FILE_MAP_READ, 0, 0, 0);
          //更新共享内存信息
          AShareInfo := pInfo;
          CloseHandle(hMapFile);
          Result := True;
        end;
      end;
    
      //检查程序是否已运行
      //参数1:程序标识
      //参数2:共享内存信息
      //返回值:程序是否已经运行
      function Check(AGuidId : string; out AShareInfo : PShareInfo) : Boolean;
      var
        hMapFile : THandle;
      begin
        Result := False;
        //检查共享内存是否已经创建
        hMapFile := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, PChar(AGuidId));
        //如果共享内存已经创建
        if hMapFile <> 0 then
        begin
          AShareInfo := MapViewOfFile(hMapFile, FILE_MAP_WRITE or FILE_MAP_READ, 0, 0, 0);
          CloseHandle(hMapFile);
          Result := True;
        end;
      end;
    
    end.
    

    测试代码:

    unit ufrmTest;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, RzEdit, uRunOnceChecker;
    
    const  MAPFILE_NAME_GUID_1 = '{1141D1B7-F276-4F31-BB01-2E2447C256BC}';
    
    const MAPFILE_NAME_GUID_2 = '{7EBAAA87-DBAC-4F69-8B77-C2D58EEFFA38}';
    
    type
      TForm1 = class(TForm)
        btnCheckOrCreate: TButton;
        btnCheck: TButton;
        btnCheckOrCreate2: TButton;
        btnCheck2: TButton;
        mmo1: TRzMemo;
        procedure btnCheckOrCreateClick(Sender: TObject);
        procedure btnCheckClick(Sender: TObject);
        procedure btnCheckOrCreate2Click(Sender: TObject);
        procedure btnCheck2Click(Sender: TObject);
      private
        procedure CheckOrCreate(AGUID : string; AName : string);
        procedure Check(AGUID : string; AName : string);
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.btnCheck2Click(Sender: TObject);
    begin
      Check(MAPFILE_NAME_GUID_2, 'B');
    end;
    
    procedure TForm1.btnCheckClick(Sender: TObject);
    begin
      Check(MAPFILE_NAME_GUID_1, 'A');
    end;
    
    procedure TForm1.btnCheckOrCreate2Click(Sender: TObject);
    begin
      CheckOrCreate(MAPFILE_NAME_GUID_2, 'B');
    end;
    
    procedure TForm1.btnCheckOrCreateClick(Sender: TObject);
    begin
      CheckOrCreate(MAPFILE_NAME_GUID_1, 'A');
    end;
    
    
    
    //检查程序是否在运行
    procedure TForm1.Check(AGUID: string; AName: string);
    var
      bRet : Boolean;
      pInfo : PShareInfo;
    begin
      mmo1.Lines.Add('检查【程序' + AName + '】-----------------------------');
      bRet := uRunOnceChecker.Check(AGUID, pInfo);
      if bRet then
      begin
        mmo1.Lines.Add('程序【' + AName + '】在运行');
      end
      else
      begin
        mmo1.Lines.Add('程序【' + AName + '】未运行');
      end;
    
    end;
    
    //检查or创建程序的共享文件内存
    procedure TForm1.CheckOrCreate(AGUID: string; AName: string);
    var
      bRet : Boolean;
      pInfo : PShareInfo;
      hApp : THandle;
      hTopWindow : HWND;
    begin
      mmo1.Lines.Add('检查or创建【程序' + AName + '】-----------------------------');
      New(pInfo);
      pInfo.AppHandle := Application.Handle;
      bRet := uRunOnceChecker.CheckOrCreate(AGUID, pInfo);
      if bRet then
      begin
        mmo1.Lines.Add('程序【' + AName + '】在运行');
        SendMessage(pInfo.AppHandle, WM_SYSCOMMAND, SC_RESTORE, 0);
        hTopWindow := GetLastActivePopup(pInfo.AppHandle);
        if (hTopWindow <> 0) and IsWindowVisible(hTopWindow) and IsWindowEnabled(hTopWindow) then
         SetForegroundWindow(hTopWindow);
      end
      else
      begin
        mmo1.Lines.Add('程序【' + AName + '】未运行,创建了共享内存');
      end;
    end;
    
    end.
    

     运行结果:

  • 相关阅读:
    几种函数调用方式
    MOSS 2010:Visual Studio 2010开发体验(11)——扩展SharePoint Explorer
    MOSS 2010:Visual Studio 2010开发体验(14)——列表开发之事件接收器
    MOSS 开发之服务帐号过期的问题
    关于工作流(Workflow Foundation)的一些总结归纳
    Infopath 2010的变化
    MOSS 2010:Visual Studio 2010开发体验(13)——列表开发之列表实例
    MTOM效率测试
    MTOM以及在WCF中的应用
    在Outlook中设置农历生日周期性事件
  • 原文地址:https://www.cnblogs.com/igaoshang/p/RunOnceChecker.html
Copyright © 2011-2022 走看看