VC和Delphi程序只运行一个实例的方法

2016-02-19 19:05 41 1 收藏

有一种朋友不在生活里,却在生命力;有一种陪伴不在身边,却在心间。图老师即在大家的生活中又在身边。这么贴心的服务你感受到了吗?话不多说下面就和大家分享VC和Delphi程序只运行一个实例的方法吧。

【 tulaoshi.com - 编程语言 】

  有些时候,我们需要我们的程序只运行一个实例,笔者自己作程序也有这样的情况,于是自已探究一番。忙活一阵后,总算小有收获,不敢独享,在天极发表出来,供大家参考。

  既然是从根本上解决问题,对于Windows程序而言,就从WinMain函数入口,这是因为在VC中使用SDK的方式编写程序最透明,并且WinMain是作为VC编译器生成EXE文件的默认入口函数。

  WinMain的函数原型:

int WinMain(
 HINSTANCE hInstance,
 HINSTANCE hPrevInstance,
 LPSTR lpCmdLine,
 int nCmdShow
);

  在WinMain中一共有四个参数,其中第二参数hPrevInstance是一个HINSTANCE,表示程序运行上一个实例的句柄。根据Msdn的说明,这个参数在Win32系统上总为NULL。不过我们还可以通过使用GreateMutex函数来创建一个唯一命名的互斥对象的方法来检测是否已经存在了另一个实例。

  GreateMutex的函数原型:

HANDLE CreateMutex(
 LPSECURITY_ATTRIBUTES lpMutexAttributes,
 BOOL bInitialOwner,
 LPCTSTR lpName
);

  第一个参数lpMutexAttributes,指向一个SECURITY_ATTRIBUTES结构的指针,用来决定是否允许子进程继承函数返回的句柄。如果这个参数为NULL(空),则不允许被继承。

  第二个参数bInitialOwner,如果这个参数为真并且是由调用者(指调用CreateMutex函数的)创建互斥对象,那么由调用的线程(调用CreateMutex函数的线程)获得最初的拥有权。除此之外,调用的线程都不能获得最初的拥有权。决定是否由调用者创建互斥对象,请看“返回值”(Return Values)小节。

  第三个函数lpName,指向用来命名互斥对象的以NULL(空)结尾的字符串,这个名字的字符个数限制在MAX_PATH个数字符内。同时这个名字区分大小写。如果参数lpName为NULL(空),将创建一个没有命名的互斥对象。如果参数lpName所指向的字符串和下列各项之中任意一项匹配:existing event,semaphore,waitable timer,job,or file-mapping object,函数将失败并伴随着调用(尽快)GetLastError函数会返回ERROR_INVALID_HANDLE常数。引发这样的结果是由于为这些互斥对象分配了重复的命名空间(这些能够引起重复的命名空间可以在Msdn中通过搜索CreateMutex查看)。

  返回值,如果函数成功,返回值是一个新创建的互斥对象的句柄。如果函数失败,返回值为NULL(空)。如果得到的互斥对象是一个在这个函数之前(指这一次调用CreateMutex函数之前)就被命名了的互斥对象并且存在,那么返回值是已存在对象的句柄,同时(尽快)调用GetLastError函数会返回ERROR_ALREADY_EXISTS。无论如何,当第二个调用者(注1)只有有限的访问权限,CreateMutex将会失败,同时会伴随着使用GetLastError返回ERROR_ACCESS_DENIED,那么调用者应该使用OpenMutex函数(更多的信息大家可以到Msdn中查看,现在这些信息已经足够我们用来保证我们的程序只运行一个实例了)。

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

  现在我确定思路:首先创建一个互斥对象,如果创建成功(CreateMutex返回值不为NULL)并调用GetLastError函数返回ERROR_ALREADY_EXISTS常数,说明当前进程不是应用程序的第一个实例,结束程序的运行。

  我们在VC中以一个没有窗口,也不用MFC的Win32应用程序作例子。打开VC6,新建一个工程,类型选择Win32 Application,工程名为:OnlyOne,单击OK,选择一个空的工程,完成。为工程添加一个新的C++源代码文件,命名为:OnlyOne.c,并输入如下代码:

#include Windows.h

int
WINAPI
WinMain(
 HINSTANCE hInstance,
 HINSTANCE hPrevInstance,
 LPSTR lpCmdLine,
 int nShowCmd
)
{
 char strAppName[] = "OnlyOne";
 HANDLE hMutex = NULL;

 //创建互斥对象
 hMutex = CreateMutex(NULL, FALSE, strAppName);
 if (hMutex != NULL)
 {
  if (GetLastError() == ERROR_ALREADY_EXISTS)
  {
   MessageBox(NULL,TEXT("不是第一次运行这个程序。"),TEXT("OnlyOne"),MB_OK | MB_ICONINFORMATION);
   //关闭互斥对象,退出程序
   CloseHandle(hMutex);
   return (-1);
  } else
  {
   MessageBox(NULL,TEXT("第一次运行这个程序。"),TEXT("OnlyOne"),MB_OK | MB_ICONINFORMATION);
  }
  } else
  {
   MessageBox(NULL,TEXT("创建互斥对象失败。"),TEXT("OnlyOne"),MB_OK | MB_ICONINFORMATION);
  }
  //关闭互斥对象
  CloseHandle(hMutex);
  return (-1);
}

  同理,这个方法适用于所有的原生Win32应用程序,能够正常调用GreateMutex和GetLastError两个函数即可,Delphi程序(这次是一个带有窗口的程序)可以参考以下步骤和代码:

  在Delphi中建立一个应用程序,然后单击菜单“Project”,单击“View Source”,这样就在代码编辑器中打开了工程文件,它的代码看起来像这样:

program OnlyOne;

uses
Forms,
uOnlyOneWindow in 'uOnlyOneWindow.pas' {OnlyOneWindow };

{$R *.res}

begin
 Application.Initialize;
 Application.CreateForm(TOnlyOneWindow, OnlyOneWindow);
 Application.Run;
end.

  我将其代码更改如下:

program OnlyOne;

uses
Windows,
Forms,
uOnlyOneWindow in 'uOnlyOneWindow.pas' {OnlyOneWindow};

{$R *.res}

var
hAppMutex: THandle;

begin
Application.Initialize;
//创建互斥对象
hAppMutex := CreateMutex(nil, false, PChar('OnlyOne'));
if (hAppMutex = 0) then
begin
 MessageBox(0,PChar('创建互斥对象失败!'),PChar('Error'),MB_OK + MB_ICONINFORMATION);
 exit;
end;
//查看是否是第一次运行程序
if ((hAppMutex 0) and (GetLastError() = ERROR_ALREADY_EXISTS)) then
begin
 MessageBox(0,PChar('不是第一次运行这个程序!'),PChar('OK'),MB_OK + MB_ICONINFORMATION);
 //关闭互斥对象,退出程序
 CloseHandle(hAppMutex);
 exit;
end;
Application.CreateForm(TOnlyOneWindow, OnlyOneWindow);
Application.Run;
//关闭互斥对象
CloseHandle(hAppMutex);
end.

  注意:

  1.在User中,要把Windows放在Form前头;

  2.开始创建互斥对象的代码要在Application.Initialize之后;

  3.关闭互斥对象操作要放在Application.Run之后;

  这样,我们只用了较少的代码和较少的系统资源消耗就实现了应用程序检测自己是否被多次运行,从而保证只运行一个示例这样的效果。

  以上程序在Visual C++ 6.0(SP6)、Delphi 7(Build 8.1)中编译,在Windows XP SP2中测试通过。

  注1:当某调用者所请求创建的互斥对象已经被命名了并且存在,这时这个调用者为“第二个调用者”。

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

来源:http://www.tulaoshi.com/n/20160219/1619995.html

延伸阅读
防止同一个程序多次运行。 '*****************方法一:防止程序多次打开*****************' 函数名: IsInstanceRunning ' 功 能: 判断工程是否已运行 ' 参 数: 无 ' 返回值: True 已运行 False 未运行 '******************************************************* Public Function IsInstanceRunning() As Boolean Dim current As Process ...
  看过几篇关于VC和Delphi比较的文章,自己也有心写写代码试试,我在VC6下新建了一个工程,叫WinTest。代码如下: #include windows.h HWND hwndButton; int cx, cy; LRESULT CALLBACK MainWndProc (HWND hWindow, UINT nMsg, WPARAM wPrm, LPARAM lPrm) {  HDC dc;  PAINTSTRUCT ps; ...
随然这个问题可能很多人都没有遇到过,但遇到过的朋友相信和我一样,都经过了一断时间的问题查找才解决,为了减少这样的问题给你带来烦恼,在此我写下此文,希望对大家有所帮助。     你是否在创建JVM是老返回-1,即JNI_ERR;总么检查程序都没有发现任可问题,编译也不会出错。动态链接库文件“jvm.dll”已经放...
GNU Emacs支持server/client这种运行方式。就类似的,UltraEditor,双击打开多个文件时,可以共用一个程序进程,每次打开文件只是在已有进程下创建一个文档标签。这个功能对于Emacs来说十分有用,因为作为开发环境,许多人的Emacs并不单纯是Emacs,也许还有ECB,也许还有CEDET,也许还有cscope等等。这些东东,每次启动Emacs都会加载半天的。但...
http://www.zdnet.com.cn/developer/code/story/0,3800066897,39250501,00.htm有时候,允许程序启动多个实例并不是一件好事。比如一个程序用来监视某个文件夹并跟踪文件夹中的新文件,这种程序只要一个实例就足够了。同样,如果一个前端数据库程序运新了多个实例,对数据库中相同内容的同时操作有可能导致数据错误。 要防止程序运行多个实例,...

经验教程

632

收藏

16
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部