利用共享内存映射实现程序只能启动一次的限制

//=============================================================================
//
// 描述: 程序单次运行检测单元
// 作者: 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.

运行结果:

时间: 2024-10-17 00:30:13

利用共享内存映射实现程序只能启动一次的限制的相关文章

.net利用程序集的GUID解决程序只能运行一次的问题

可以解决同名的程序集(但非同一程序集)只能运行一次的问题,网上很资料都是只检测程序是否同名,不能真正的保证是同一程序集. private bool prevInstance() { Process[] myProcesses= Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName); if (myProcesses.Length > 1) { GuidAttribute curGuid = (GuidAttribut

[转]Windows环境下利用“共享内存”实现进程间通信的C/C++代码---利用CreateFileMapping和MapViewOfFile

http://blog.csdn.net/stpeace/article/details/39534361 进程间的通信方式有很多种, 上次我们说了最傻瓜的“共享外存/文件”的方法. 那么, 在本文中, 我们即将学习“共享内存”的方式实现进程间的通信, 这是IPC最快的方法.有的地方又把这种“共享内存”的方式叫做“内存映射文件”方式. 我们首先来看看进程A对应的程序: #include <iostream> #include <windows.h> using namespace

『Numpy』内存分析_利用共享内存创建数组

引.内存探究常用函数 id(),查询对象标识,通常返回的是对象的地址 sys.getsizeof(),返回的是 这个对象所占用的空间大小,对于数组来说,除了数组中每个值占用空间外,数组对象还会存储数组长度.数组类型等其他信息 numpy.ndarray.ctypes.data属性,返回numpy数组的内存位置 array.array.buffer_info(),数组对象的内存信息,返回元素起始地址和元素个数 help(array.buffer_info)'''buffer_info(self,

(转)linux用文件锁实现保证一个程序只能启动一个进程

#include <stdio.h> #include <unistd.h>#include <fcntl.h>#include <errno.h>int main(int argc,char* argv[]){ int fd; int lock_result; struct flock lock; char * pFileName = "tmp.lck"; fd = open(pFileName,O_RDWR); if(fd<0)

共享内存之——mmap内存映射

共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制.共享内存可以通过mmap()映射普通文件 (特殊情况下还可以采用匿名映射)机制实现,也可以通过systemV共享内存机制实现.应用接口和原理很简单,内部机制复杂.为了实现更安全通信,往往还与信号灯等同步机制共同使用. 这一篇详解mmap内存文件映射原理及其案例,system V共享内存 以及他们的区别将在后面的随笔中讨论. 非原创,内容源于互联网 mmap内存文件映射 一.传统文件访问 unix

计算机程序的思维逻辑 (61) - 内存映射文件及其应用 - 实现一个简单的消息队列

本节介绍内存映射文件,内存映射文件不是Java引入的概念,而是操作系统提供的一种功能,大部分操作系统都支持. 我们先来介绍内存映射文件的基本概念,它是什么,能解决什么问题,然后我们介绍如何在Java中使用,我们会设计和实现一个简单的.持久化的.跨程序的消息队列来演示内存映射文件的应用. 基本概念 所谓内存映射文件,就是将文件映射到内存,文件对应于内存中的一个字节数组,对文件的操作变为对这个字节数组的操作,而字节数组的操作直接映射到文件上.这种映射可以是映射文件全部区域,也可以是只映射一部分区域.

Boost:shared_memory_object --- 共享内存

什么是共享内存 共享内存是最快速的进程间通信机制.操作系统在几个进程的地址空间上映射一段内存,然后这几个进程可以在不需要调用操作系统函数的情况下在那段内存上进行读/写操作.但是,在进程读写共享内存时,我们需要一些同步机制. 考虑一下服务端进程使用网络机制在同一台机器上发送一个HTML文件至客户端将会发生什么: 服务端必须读取这个文件至内存,然后将其传至网络函数,这些网络函数拷贝那段内存至操作系统的内部内存. 客户端使用那些网络函数从操作系统的内部内存拷贝数据至它自己的内存. 如上所示,这里存在两

Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存

Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存 参考:<linux编程从入门到精通>,<Linux C程序设计大全>,<unix环境高级编程> 参考:C和指针学习 说明:本文非常的长,也是为了便于查找和比较,所以放在一起了 Linux 传统的进程间通信有很多,如各类管道.消息队列.内存共享.信号量等等.但它们都无法介于内核态与用户态使用,原因如表 通信方法 无法介于内核态与用户态的原因 管道(不包括命名管道) 局限于父子进程间的通信. 消息队列 在

Linux共享内存使用常见陷阱与分析

所谓共享内存就是使得多个进程可以访问同一块内存空间,是最快的可用IPC形式.是针对其他通信机制运行效率较低而设计的.往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥.其他进程能把同一段共享内存段“连接到”他们自己的地址空间里去.所有进程都能访问共享内存中的地址.如果一个进程向这段共享内存写了数据,所做的改动会即时被有访问同一段共享内存的其他进程看到.共享内存的使用大大降低了在大规模数据处理过程中内存的消耗,但是共享内存的使用中有很多的陷阱,一不注意就很容易导致程序崩溃. 超过共享内