Delphi防止同时出现多个应用程序实例
delphi mdi 原理
Delphi是一种编程语言和集成开发环境(IDE),支持多文档界面(MDI)应用程序的开发。
MDI是一种用户界面设计模式,允许在一个主窗口中同时打开多个子窗口。
在Delphi中,MDI应用程序的原理如下:
1. 创建主窗口:首先,你需要创建一个主窗口,它将包含所有的子窗口。
你可以使用Delphi的窗体设计器来创建主窗口。
2. 创建子窗口:接下来,你需要创建子窗口。
子窗口是主窗口的子控件,可以在主窗口中显示。
你可以使用Delphi的窗体设计器或代码来创建子窗口。
3. 设置主窗口属性:在主窗口上,你需要设置一些属性来启用MDI功能。
你可以将主窗口的FormStyle属性设置为fsMDIForm,这将使主窗口成为MDI容器。
4. 设置子窗口属性:在子窗口上,你需要设置一些属性来使其成为MDI子窗口。
你可以将子窗口的FormStyle属性设置为fsMDIChild,这将使子窗口成为MDI容器的子控件。
5. 打开子窗口:当用户需要打开一个子窗口时,你可以使用
Delphi的代码来创建一个新的子窗口实例,并将其添加到主窗口的子控件列表中。
6. 切换子窗口:用户可以通过点击主窗口的标题栏或使用菜单或工具栏来切换子窗口。
当用户切换子窗口时,主窗口会自动将当前活动的子窗口显示在前面。
7. 关闭子窗口:当用户关闭一个子窗口时,你需要从主窗口的子控件列表中移除该子窗口,并释放其资源。
通过以上步骤,你可以在Delphi中创建一个MDI应用程序,允许用户同时打开多个子窗口,并在主窗口中进行切换和管理。
delphi waitformultipleobjects event
delphi waitformultipleobjects event在Delphi中,WaitForMultipleObjects函数是Windows API函数,用于使线程等待一组句柄中的任何一个变得可用。
当你要在Delphi中创建一个多线程应用程序,并需要等待多个事件或对象时,可以使用这个函数。
WaitForMultipleObjects函数的原型如下:pascalfunction WaitForMultipleObjects(Count: Longint;const Objects: array of PObject;WaitAll: Boolean;Timeout: Longint = -1): Longint; stdcall;其中,Objects参数是一个指向对象数组的指针,数组中的每个对象都可以是一个窗口句柄、事件对象句柄、进程句柄、线程句柄等。
如果你想要等待一个或多个事件发生,可以将这些事件的句柄放入一个数组中,并传递给WaitForMultipleObjects函数。
当任何一个事件发生时,函数就会返回,并告知哪个事件已经发生。
下面是一个简单的示例,演示如何使用WaitForMultipleObjects函数等待两个事件:pascalvarEvents: array[0..1] of THandle;Ret: Longint;beginEvents[0] := CreateEvent(nil, False, False, nil);Events[1] := CreateEvent(nil, False, False, nil);// 等待两个事件中的任何一个发生Ret := WaitForMultipleObjects(2, Events, False, INFINITE);if Ret = WAIT_OBJECT_0 thenShowMessage('Event 1 signaled')else if Ret = WAIT_OBJECT_0 + 1thenShowMessage('Event 2 signaled');end;在上面的示例中,我们创建了两个事件对象,并将它们的句柄存储在Events数组中。
如何防止程序打开多个实例
( 兴文理学 院 绍 实 验 中心 , 江 浙 绍 兴 320 ) 100
摘
要 : Ⅶ 编程 为 例 探 讨 了 防止 程 序 打 开 多 个 实 例 的 3 行 之 有 效 的 方 案 , 进 行 了对 比 分 析 , 时 还 给 出 了 一 个 具 有 以 个 并 同
相 当 实 用 价值 的 “ 索 程 序 ” 数 . 搜 函 关 键 词 :id n o 搜 索 ; P F Widw; n AI
维普资讯
第 2卷 第 2 2 期 20 0 2年 6月
绍
‘
兴
文
理
学
院
学
报
Vo . 122 No. 2
J 讯 NAI OI .OF S HAOX1 G N UNI ERSI V TY
J n. 0 2 u 20
如何 防止程序打开 多个 实例
De lr u c o n W id w b “ s r 2’ ca e F n t n Fid n o Li u e3 ’Ala “ i d i d wA” i i s Fn W n o
一
Байду номын сангаас
( y a lCas a eA tn , y a lWidw a eA tn )A n B V l p l N m sS i B V l p n o N m s r g sL g s rg Si o
妙.
( ) Widw T环 境下 使 用 A p PeIs n e的部件 可 能 引起 问题 . 2在 nos N p .rv t c na 由于运 行 Wi o s T的计 算机 n w d N 可 以支 持 多个 桌 面系统 ( e t s , ds o ) 当使 用 为 与分布 的 C M 一 道工 作 而设 计 的部 件 时 , kp O 有可 能 有该 部 件 的 两个 实例 运行 在 同一 个 N T计算 机 的不 同的桌 面系 统 上 . 如 果 部 件 的作 者 已在 部 件 的启 动 代 码 中放 了 但
限制一个程序同时只能运行一个实例的方法
限制一个程序同时只能运行一个实例的方法限制一个程序同时只能运行一个实例的方法一般有两种,即使用“信号”与FindWindow,通常第一种方法较为安全,而第二种方法必须知道Window的CLASS(在MFC中是很痛苦的,而且一旦CLASS NAME变了以后程序也要跟着改),否则可能就会出错。
然而这两种方法都只能限制程序运行一次,如果要控制程序运行次数,比如3次,则使用以上的两种方法就会很困难。
前段时间写了一个HOOK函数,其中用到了共享变量,在这个程序写完后我突发奇想,不知道这个东西在EXE文件中是否有用?想到了那就试一试吧,一试,果然蛮爽的,居然也行,当时就想到这样一来如果要限制一个程序同时只能运行一个实例不是很简单,试了一下,当然毫无疑问的程序只运行了一个,代码如下:1、在一个CPP中所有函数实体外加入以下几句#pragma data_seg("SHARDAT")HWND ghMainWnd=NULL; //必须初始化,保存主窗口HANDLE#pragma data_seg()#pragma comment(linker,"/section:SHARDA T,RWS")2、在你的主窗口的OnCreate中对ghMainWnd赋值ghMainWnd = GetSafeHwnd();3、程序运行时(如Initinstance)判断ghMainWnd 是否为NULLif( ghMainWnd!=NULL && IsWindow(ghMainWnd) ){SendMessage( ghMainWnd, WM_YOURMESSAGE, ...return ...}怎么样,比第一种方法简单多了吧,有了以上代码,要限制程序运行次数就简单了,如下:1、在一个CPP中所有函数实体外加入以下几句#pragma data_seg("SHARDAT")HWND ghMainWnd[10]={}; //保存已运行的窗口HANDLE,没太多用int gRuned=0;#pragma data_seg()#pragma comment(linker,"/section:SHARDA T,RWS")2、在你的主窗口的OnCreate中对ghMainWnd赋值if( gRuned<10 )ghMainWnd[gRuned] = GetSafeHwnd();gRuned++;3、注意,必须在适当的时候减小gRuned, 如在OnDestroy中等4、程序运行时(如Initinstance)判断ghMainWnd 是否为NULLif( gRuned>=MAX_RUN ){SendMessage( ghMainWnd, WM_YOURMESSAGE, ...return ...}注意:在对gRuned操作时要注意同步其中MAX_RUN可以保存到REG或INI中,根据不同情况来设定。
delphi多页组件(TPageControl)使用方法详解实例
? GoForward 参数:取值为Boolean 类型,True 值取下一页,False 值取上一页。
? CheckTabVisible 参数:取值为Boolean 类型,True 值为检查TTabSheet 的TabVisible 属性,如果TabVisible 属性为False,则不显示此页而直接跳至下一页或上一页;如果CheckTabVisible 参数为False,则不检查TTabSheet 的TabVisible 属性,即不管TabVisible 属性为True 还是False,都显示这一页的内容。
TPageControl 组件是一组页面集,用于构造一个多页对话框,它显示多个交互页(TTabSheet 对象),用户通过选择出现在控制上部的标签,可以选择不同的页。在设计时要加入新页,用鼠标右键单击该组件对象,出现一弹出菜单,选择“New Page”菜单项。
此组件用于需要显示大量信息的时候,屏幕上不可能把这些信息同时显示出来,解决的办法之一就是打开多个窗口,但是要管理好这些窗口不是一件很简单的事。最好的解决办法就是把这些信息分门别类,放在同一个窗口的不同页上,这样能够节省大量的屏幕空间,翻阅起来又非常方便,就好比一本书,如果把书的每一页拆下摊在桌子上,要占很大的地方,如果装订成书,就只占一本书的地方。
2.TPageControl 组件的重要属性
·ActivePage 指定或返回当前活动的页
·ActivePageIndex 此属性可以使某个序号的页成为当前活动的页
·Images 此属性用于指定一个图像列表
·PageCount 此属性返回多页组件的页数
·Pages 此属性返回由多页组件上所有页组成的数组
delphi中,让程序只运行一次的方法
if WaitForSingleObject(myMutex,0)<>wait_TimeOut then
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
下面是详细代码。
注意:下面代码在delphi7下运行通过。但是如果窗口最小化后,再次运行程序时,原先已经运行的程序能够被置前并激活但是标题栏的最小化按钮却不能用了。当尝试了N中方法后估计是delphi自身TForm类的问题,下面给出一个解决方案:在窗口上放一个ApplicationEvents控件,它管理着应用程序所有的消息。我们在它的OnMessage事件里写上下面的代码:
ClassName := pchar(ClassName); //在字符串后加结束符,确定字符串结束
if UpperCase(ClassName) = UpperCase(TForm1.ClassName) then //比较类名
begin
WinInstance := GetWindowLong(hwnd, GWL_HINSTANCE); //获得当前遍历窗口的实例
注意:以下的代码都出现在工程文件中,而不是单元文件中。
var
myMutex:HWND;
begin
//CreateMutex建立互斥对象,并且给互斥对象起一个唯一的名字。
myMutex:=CreateMutex(nil,false,'hkOneCopy');
Application.CreateForm(TForm1, Form1);
Application.Run;
delphi中,让程序只运行一次的方法
公司开发的软件需要对串口进行*作,每次打开软件后程序自动去打开串口寻找连接到串口上的设备,但是如果用户不知道打开了两次,那么第二次打开的程序是不能正常使用的,因为对串口的*作时独占的,第一个程序独占了串口的使用权,其他程序无法再使用那一个串口,当然如果PC机器上有两个串口,那第二个程序也是可以用的。
为了解决这个问题,必须限制对串口*作的软件只能打开一个。
打开软件后用户如果误*作再次想打开该软件,需要提示用户软件已经打开,并让已打开的软件显示在窗口最顶层。
下面是Delphi版的解决方法。
(方法一)利用互斥对象开发过多线程软件的可能都使用过互斥对象,它常被用做线程间同步的技术手段。
简要的提一下互斥对象:互斥对象把第一次建立它的程序作为主程序,这样只用检测互斥对象是否已经有主程序就判断程序是否已经运行过,这里需要涉及到一个api函数:WaitForSingleObject,该函数的第一个参数为用以检测的互斥对象,第2个参数的表示函数返回结果前的滞留时间,如果改函数返回wait_TimeOut就表明互斥对象已经有了一个主程序。
注意:以下的代码都出现在工程文件中,而不是单元文件中。
varmyMutex:HWND;begin//CreateMutex建立互斥对象,并且给互斥对象起一个唯一的名字。
myMutex:=CreateMutex(nil,false,'hkOneCopy');//程序没有被运行过if WaitForSingleObject(myMutex,0)<>wait_TimeOut thenbeginApplication.Initialize;Application.CreateForm(TForm1, Form1);Application.Run;End;End;[注释]:当应用程序第一次运行的时候,在应用程序中会建立一个互斥对象,名称为'hkOneCopy',然后判断系统中有没有这个互斥对象,如果没有则初始化应用程序。
delphi qworker用法
delphi qworker用法
Delphi是一种强大的编程语言,它提供了许多工具和组件,以便开发人员可以更轻松地创建高效的应用程序。
其中一个非常有用的组件就是QWorker,它可以帮助开发人员更好地管理并发任务。
QWorker是一个用于多线程编程的Delphi组件,它可以帮助开发人员在应用程序中实现并行处理,从而提高程序的性能和响应速度。
使用QWorker,开发人员可以轻松地创建并发任务,并在多个线程中同时执行这些任务。
QWorker的用法非常简单,开发人员只需要创建一个QWorker 对象,然后将需要并行处理的任务传递给该对象即可。
QWorker会自动创建并管理线程,以确保任务能够在多个线程中同时执行。
开发人员还可以使用QWorker提供的一些方法和属性来监控并发任务的执行情况,以及在需要时对任务进行控制。
除了简单的并行处理,QWorker还提供了一些高级功能,比如任务调度、任务优先级控制、任务取消等。
这些功能可以帮助开发人员更好地管理并发任务,以及更灵活地控制任务的执行方式。
总的来说,QWorker是一个非常有用的Delphi组件,它可以帮
助开发人员更好地实现并发任务,提高应用程序的性能和响应速度。
通过合理地使用QWorker,开发人员可以更轻松地编写高效的多线
程应用程序,从而为用户提供更好的使用体验。
Delphi实现窗体内嵌其他应用程序窗体
Delphi实现窗体内嵌其他应用程序窗体[代码]Delphi实现窗体内嵌其他应用程序窗体实现原理是启动一个应用程序,通过ProcessID得到窗体句柄,然后对其设定父窗体句柄为本程序某控件句柄(本例是窗体内一个Panel的句柄),这样就达成了内嵌的效果。
本文实现的是内嵌一个记事本程序,如下图:在实现细节上需要注意几点:1.为了美化程序的嵌入效果,需要隐藏其标题栏2.在外部窗体大小变化时,需要内嵌的窗体也随之变化大小3.外部程序退出时,内嵌的程序也要退出下面是例子程序。
新建窗体,上面放置一个Panel控件,名为pnlApp,然后按下面代码编写:unit frmTestEmbedApp;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, ExtCtrls;typeTForm1 = class(TForm)pnlApp: TPanel;procedure FormCreate(Sender: TObject);procedure FormClose(Sender: TObject; var Action: TCloseAction);procedure FormResize(Sender: TObject);private{ Private declarations }public{ Public declarations }end;varForm1: TForm1;hWin: HWND = 0;implementation{$R *.dfm}type// 存储窗体信息PProcessWindow = ^TProcessWindow;TProcessWindow = recordProcessID: Cardinal;FoundWindow: hWnd;end;// 窗体枚举函数function EnumWindowsProc(Wnd: HWND; ProcWndInfo: PProcessWindow): BOOL; stdcall;varWndProcessID: Cardinal;beginGetWindowThreadProcessId(Wnd, @WndProcessID);if WndProcessID = ProcWndInfo^.ProcessID then beginProcWndInfo^.FoundWindow := Wnd;Result := False; // 已找到,故停止EnumWindowsendelseResult := True; // 继续查找end;// 由 ProcessID 查找窗体 Handlefunction GetProcessWindow(ProcessID: Cardinal): HWND;varProcWndInfo: TProcessWindow;beginProcWndInfo.ProcessID := ProcessID;ProcWndInfo.FoundWindow := 0;EnumWindows(@EnumWindowsProc,Integer(@ProcWndInfo)); // 查找窗体Result := ProcWndInfo.FoundWindow;end;// 在 Panel 上内嵌运行程序function RunAppInPanel(const AppFileName: string; ParentHandle: HWND; var WinHandle: HWND): Boolean;varsi: STARTUPINFO;pi: TProcessInformation;beginResult := False;// 启动进程FillChar(si, SizeOf(si), 0);si.cb := SizeOf(si);si.wShowWindow := SW_SHOW;if not CreateProcess(nil, PChar(AppFileName), nil, nil, true,CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, si, pi) then Exit;// 等待进程启动WaitForInputIdle(pi.hProcess, 10000);// 取得进程的 HandleWinHandle := GetProcessWindow(pi.dwProcessID);if WinHandle > 0 then begin// 设定父窗体Windows.SetParent(WinHandle, ParentHandle);// 设定窗体位置SetWindowPos(WinHandle, 0, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOZORDER);// 去掉标题栏SetWindowLong(WinHandle, GWL_STYLE, GetWindowLong(WinHandle, GWL_STYLE)and (not WS_CAPTION) and (not WS_BORDER) and (not WS_THICKFRAME));Result := True;end;// 释放 HandleCloseHandle(pi.hProcess);CloseHandle(pi.hThread);end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);begin// 退出时向内嵌程序发关闭消息if hWin > 0 then PostMessage(hWin, WM_CLOSE, 0, 0);end;procedure TForm1.FormCreate(Sender: TObject);constApp = 'C:\Windows\Notepad.exe';beginpnlApp.Align := alClient;// 启动内嵌程序if not RunAppInPanel(App, pnlApp.Handle, hWin) then ShowMessage('App not found');end;procedure TForm1.FormResize(Sender: TObject);begin// 保持内嵌程序充满 pnlAppif hWin <> 0 then MoveWindow(hWin, 0, 0, pnlApp.ClientWidth, pnlApp.ClientHeight, True);end;end.这种方式也存在几个问题:问题1:如果程序有Splash窗体先显示,则实际窗体无法内嵌,因为仅将Splash窗体的父窗体设定为本程序的控件句柄,后续窗体无法设定。
DELPHI多线程编程
我们知道, WIN95或WIN NT都是"多线程"的操作系统,在Delphi2.0中,我们可以充分利用这一特性,编写出"多线程"的应用程序。
对以往在DOS或16位windows下写程序的人来说,"多线程"仍然是陌生的,但如同以前我们从DOS下的单任务过渡到windows 3.1下的多任务,如今我们又必须过渡到"多线程"领域,毕竟计算机时代是在不断发展的。
不过,幸运的是,在Delphi2.0下进行多线程程序设计并不需要我们去学习庞大的WIN32API函数,我们可以利用Delphi 下标准的多线程类TThread来完成我们的工作。
TThread是一个abstract(抽象)类,也就是说,并不需要根据TThread来声明变量(而且根据TThread声明的变量也是完全无用),我们要做的是把TThread作为基类,用继承的形式来生成子类。
实际上,根据TThread来写多线程应用程序是非常容易的。
下面就是一个基本的继承TThread生成的多线程类。
QuerThrd.PasUnit QuerThrd;InterfaceUsesClasses,DBTables;TypeTQueryThread=class(TThread)privatefQuery:TQuery;protectedprocedure Execute;override;publicconstructor Create(Suspended:Boolean; Query:TQuery);end;implementationconstructorTQueryThread.Create(Suspended:Boolean;Query:TQuery);begininheritedCreate(Suspended);fQuery:=Query;FreeOnTerminate:=True;end;procedure TQueryThread.Execute;beginfQuery.Open;end;end.在上面这个简单的例子中,我们构造了一个TThread的子类TQueryThread,用于在后台执行数据库查询。
delphi不同项目引用相同单元注意事项
delphi不同项目引用相同单元注意事项在Delphi中,单元是代码的基本组成部分,它们包含了一些可重用的代码,可以在不同的项目中使用。
当我们在不同的项目中引用相同的单元时,需要注意一些问题,以确保代码的正确性和可维护性。
1. 命名空间在Delphi中,命名空间是指在代码中定义的标识符的作用域。
当我们在不同的项目中引用相同的单元时,需要确保它们的命名空间不会冲突。
为了避免命名空间冲突,我们可以使用不同的单元前缀或命名空间。
例如,我们可以在单元中定义一个命名空间:unit MyUnit;interfaceusesSystem.Classes;typeMyNamespace = class...end;implementationend.然后在不同的项目中使用该单元时,可以使用不同的前缀或命名空间:unit Project1;interfaceusesMyUnit;typeTProject1 = class...end;implementationend.unit Project2;interfaceusesMyUnit;typeTProject2 = class...end;implementationend.这样,即使在不同的项目中使用相同的单元,也不会出现命名空间冲突的问题。
2. 版本控制当我们在不同的项目中使用相同的单元时,需要确保它们的版本是一致的。
如果不同的项目使用不同的单元版本,可能会导致代码不兼容或出现错误。
为了避免这种情况,我们可以使用版本控制工具来管理单元的版本。
例如,我们可以使用Git或SVN等版本控制工具来管理单元的代码,并确保不同的项目使用相同的版本。
3. 依赖关系当我们在不同的项目中使用相同的单元时,需要确保它们的依赖关系是正确的。
如果一个项目依赖于另一个项目中的单元,但是没有正确地引用它,可能会导致编译错误或运行时错误。
为了避免这种情况,我们可以使用包管理工具来管理单元的依赖关系。
程序防止多开分析游戏多开原理
3、效果这个是非常简单的应用程序多开检测,一般的程序多开器均能破解此限制。
二、使用窗口属性1、原理在程序启动时,枚举桌面所有窗口,并检查其属性列表中是否存在特殊的属性值,如果有则表明程序已经启动,否则程序未启动。
2、实现3、效果没有做过多的测试,手头有两个多开器均不能多开。
三、使用公共文件1、原理程序启动时,在一个公共目录(比如C:\或者Temp目录)中创建一个公共文件,并将此文件设置为不共享读写。
第二个程序启动时,也打开此文件,如果打开成功,则表示程序未启动过,否则表示程序已经启动。
2、实现此方法实现较为简单,不做详细说明了,请自行查阅CFile等相关文件操作。
3、效果多开器肯定是不能够多开了,但是可以手动设置多开。
比如:设定文件访问权限,不允许此程序在公共目录创建文件等。
应对方法就是,如果不能创建文件则程序不允许运行。
四、mac地址验证1、原理必须是网络应用程序,如果单机运行,此方法无效。
登陆服务器时,获取本机mac地址,发送至服务器端,服务端进行mac地址验证,如果mac地址重复登陆,则不允许同服务器进行消息传递。
2、实现客户端主要是mac地址获取,这个问题我至今没有找到太好的解决方案,效果较好的方法是读取注册表获取。
首先使用GetAdaptersInfo函数获取所有网卡信息,然后,对于每一个网卡信息查找注册表HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\网卡名称\\Connection位置,如果MediaSubType的值为0x01并且PnpInstanceID中含有PCI字串则表示是物理网卡。
3、效果差强人意,多开器倒是不能用了,但是可以使用超级兔子等软件修改mac地址实现。
五、查看网络连接3、效果多开器肯定不能用,但有其他方式导致GetTcpTable函数失败(比如挂系统钩子等)。
pyside6防止程序多开的方法 -回复
pyside6防止程序多开的方法-回复如何使用PySide6 防止程序多开引言:在开发应用程序时,有时我们希望确保用户只能同时运行一个实例。
这是为了防止用户无意中打开多个相同的应用程序窗口,或者在多个窗口之间共享资源时产生冲突。
在本文中,我们将探讨如何使用PySide6,一个用于创建跨平台桌面应用程序的Python 框架,来防止程序多开的方法。
步骤1:检测当前是否有程序已经在运行要实现防止程序多开的功能,首先我们需要检测当前是否已经有程序实例在运行。
为此,我们可以使用PySide6 的QSingleApplication 类。
QSingleApplication 类是PySide6 提供的一个用于创建单例应用程序实例的类。
以下是使用QSingleApplication 类检测程序是否已经在运行的示例代码:pythonfrom PySide6.QtWidgets import QApplicationfrom PySide6.QtCore import QSingleApplicationapp = QApplication([])# 使用应用程序的唯一标识符初始化QSingleApplicationsingle_app = QSingleApplication("MyApp")# 检查是否已经有程序实例在运行if single_app.isRunning():print("程序已经在运行!")# 程序已经在运行,可以退出当前实例的运行app.quit()else:# 未检测到其他程序实例,可以继续初始化主窗口等操作print("程序未在运行!")#TODO: 初始化主窗口以及其他操作# 运行应用程序app.exec()在上述示例代码中,我们首先初始化了一个QApplication 对象。
然后,我们使用应用程序的唯一标识符初始化了一个QSingleApplication 对象。
delphi中sharemem的作用
Delphi是一种基于Object Pascal语言的集成开发环境(IDE),通常用于构建Windows评台下的应用程序。
在Delphi中,有一个重要的概念叫做sharemem,它在应用程序开发中起着至关重要的作用。
本文将对sharemem的作用进行深入探讨,并就其在Delphi应用程序开发中的应用进行详细介绍。
一、sharemem的概念1. sharemem的定义sharemem是Delphi中的一个单元(unit),它提供了一种共享动态信息库(DLL)中的内存管理机制。
简单的说,它允许多个应用程序实例之间共享内存,从而实现数据共享。
2. sharemem的特点- 为了保证内存的正确共享,sharemem单元提供了一组函数和过程,用于动态分配和释放内存、以及在多个应用程序实例之间进行内存数据的传递和共享。
- 在使用sharemem的应用程序中,所有的数据结构和对象都需要在内存中进行分配和管理,以确保数据可以被正确地共享和访问。
二、sharemem的作用1. 支持动态信息库(DLL)的内存共享在很多实际的应用场景中,我们需要将一些数据结构、对象实例等存储在动态信息库(DLL)中,以便多个应用程序实例可以共享这些数据。
而使用sharemem单元,就可以很方便地实现DLL内存共享的功能。
2. 跨应用程序实例的数据共享通过sharemem单元提供的内存分配和管理功能,不同的应用程序实例可以共享同一块内存区域,从而实现数据的共享和传递。
这对于一些需要跨应用程序实例之间进行数据交换和通信的应用程序来说,具有非常重要的意义。
3. 提高应用程序的性能由于多个应用程序实例可以共享内存,避免了多次重复的内存分配和数据拷贝操作,因此能够显著提高应用程序的性能。
三、sharemem的应用实例1. 在多线程应用程序中的应用在使用Delphi编写多线程应用程序时,通常会涉及到多个线程之间的数据共享和通信。
这时,可以通过sharemem单元提供的功能,实现多线程之间的内存数据共享,从而实现线程之间的信息交换和同步。
用DDE实现窗体防止运行多个实例并传递命令
给个文章你们看看吧!用DDE实现窗体防止运行多个实例并传递命令关键字:VB,DDE,实例,命令贴文时间使用DDE技术,为您的应用程序增辉上网的朋友一定都用过网络蚂蚁(Net Ants)的吧?不知你在使用过程中有没有注意过,那就是如果你想调动两个“蚂蚁”为您效力是不可能的--它总会把新运行的关闭。
这点在VB 中很容易实现:Private Sub Form_Load()If App.PrevInstance ThenMsgBox "你已经运行这个应用程序了"End ' 退出新运行的程序End IfEnd Sub这样如果你运行这个程序后在运行它,它会弹出一个消息框并拒绝再次运行。
这非常容易。
而“蚂蚁”程序的妙处就在于:在重复运行“蚂蚁”时它不仅拒绝运行,而且能把已经运行的“蚂蚁”激活,这样用上面的程序就无能为力了。
但事实上实现拒绝运行并激活已运行的程序有多种方法:1、用FindWindow函数得到已经运行窗体的句柄(HWND),然后用SetActiveWindow 等API函数将其激活。
其缺点也很明显,那就是没法传递参数。
2、用FindWindow函数得到已运行窗体的句柄后用SendMessage的方法给窗体传送一个自定义消息(附带参数),然后在窗体中拦截并进行处理,但这样做要修改窗体的标准消息处理程序,用在VC,BC或DELPHI编写的程序中还行,但在VB中工作量太大,并且容易发生“一般保护行错误”使VB崩溃,不太可取(当然,如果你有足够的信心和不怕崩溃的精神,也可以试一下^_^ )。
3、使用DDE技术。
所谓DDE技术,就是动态数据交换技术。
也许你很奇怪,这与本文所讨论的内容有什么相干的?且听我慢慢讲来。
为了实现拒绝运行并把已经运行的程序激活并实现各种功能,我们可以先用本文开头提到的方法,检测一下程序有没有被运行过,如果没有,就正常运行,如果已经被运行过,就打通与它的DDE通道,传给它一个(或一些)数据,然后由已经运行的程序对数据进行处理,再去实现各种“意想不到”的功能,这时也许就有人对这你的程序喊:“酷、酷……” ^_^ 好了,耳听为虚,眼见为实,下面让我们动点真格的。
Delphi程序只能打开一个的方法
工作上,避免我的Up load在一个电脑上被打开多个。
1、新建一个un it名字是保存为'once.pas' ,内容如下:unit once;interf aceusesWindow s ,Messag es, SysUti ls, Classe s, Forms;implem entat ionconstSTR_UN IQUE= '{2BE6D96E-827F-4BF9-B33E-8740412CDE96}';MI_ACT IVEAP P =1; {激活应用程序}MI_GET HANDL E =2; {取得句柄}variMessa geID: Intege r;OldWPr oc : TFNWnd Proc;MutHan dle : THandl e;BSMRec ipien ts : DWORD;functi on NewWnd Proc(Handle: HWND; Msg: Intege r; wParam, lParam:Longin t): Longin t; stdcal l;beginResult := 0;if Msg = iMessa geIDthenbegincase wParam ofMI_ACT IVEAP P: {激活应用程序}if lParam<>0 thenbegin{收到消息的激活前一个实例}{为什么要在另一个程序中激活?}{因为在同一个进程中Se tFore groun dWind ow并不能把窗体提到最前}if IsIcon ic(lParam) thenOpenIc on(lParam)elseSetFor egrou ndWin dow(lParam);Applic ation.Termin ate; {终止本实例}end;MI_GET HANDL E: {取得程序句柄}beginPostMe ssage(HWND(lParam), iMessa geID, MI_ACT IVEAP P,Applic ation.Handle);end;end;endelseResult :=CallWi ndowP roc(OldWPr oc, Handle, Msg, wParam, lParam);end;proced ure InitIn stanc e;begin{取代应用程序的消息处理}OldWPr oc := TFNWnd Proc(SetWin dowLo ng(Applic ation.Handle, GWL_WN DPROC, Longin t(@NewWnd Proc)));{打开互斥对象}MutHan dle := OpenMu tex(MUTEX_ALL_A CCESS, False,STR_UN IQUE);if MutHan dle = 0 thenbegin{建立互斥对象}MutHan dle := Create Mutex(nil,False, STR_UN IQUE);endelse beginApplic ation.ShowMa inFor m := False;{已经有程序实例,广播消息取得实例句柄}BSMRec ipien ts :=BSM_AP PLICA TIONS;BroadC astSy stemM essag e(BSF_IG NOREC URREN TTASK or BSF_PO STMES SAGE, @BSMRec ipien ts, iMessa geID, MI_GET HANDL E,Applic ation.Handle);end;end;initia lizat ion{注册消息}iMessa geID:=Regist erWin dowMe ssage(STR_UN IQUE);InitIn stanc e;finali zatio n{还原消息处理过程}if OldWPr oc <> Nil thenSetWin dowLo ng(Applic ation.Handle, GWL_WN DPROC,LongIn t(OldWPr oc));{关闭互斥对象}if MutHan dle <> 0thenCloseH andle(MutHan dle);end.2、把这个onc e.pas考到upload(我的工作程序里),然后打开Up Load程序(也可以是你自己的程序),点击Proj ect---->Add to Projec t 然后选中once.pas 点确定,编译执行你的程序就可以了。
防止应用程序开启多个实例的若干方法
防止应用程序开启多个实例的若干方法
鲁礼炳;王明芬
【期刊名称】《电脑知识与技术-经验技巧》
【年(卷),期】2003(000)032
【摘要】在应用程序开发过程中,根据实际应用和操作的需要,应该给应用程序增加“防止应用程序开启多个实例”的功能,以免开启应用程序的多个实例。
完成此功能,方案较多。
笔者经过在实际应用开发中的探索,总结出如下若干方法(共五种方法),每种方法各具特色且所涉及到的技术也略有不同。
下面就各种方法分别作详细的分析介绍。
【总页数】3页(P46-48)
【作者】鲁礼炳;王明芬
【作者单位】无
【正文语种】中文
【中图分类】TP311.1
【相关文献】
1.防止程序开启多个实例的终结篇 [J], 舒嵩嵩
2.用内存映射文件防止应用程序运行多个实例 [J], 王德明;孙波
3.限制Windows应用程序多个实例的方法 [J], 戴志远
4.限制Windows应用程序多个实例的方法 [J], 戴志远
5.限制Windows应用程序多个实例的方法 [J], 戴志远
因版权原因,仅展示原文概要,查看原文内容请购买。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
多实例指同时有同一个应用程序的多个副本在运行。
同一个应用程序的多个副本可以相互独立地同时运行,是Win32操作系统提供的一个功能。
但有时,我们可能希望用户启动应用程序后就不再启动它的别的副本。
比如某种设备资源的控制程序,像调制解调器和并行端口。
这种情况下,用程序代码防止同时出现多个程序的副本在运行是非常必要的。
在16位的Windows中,要防止出现多个实例是很简单的,因为系统变量hPrevInst 可以被用来判断是否有其他的实例存在。
当hPrevInst变量不为0时,表示已经有别的应用程序实例在运行。
然而,在Win32系统中每个进程之间有R32绝缘层来彼此隔绝。
因此,在Win32系统中变量hPrevInst的值总为0。
另一种既适合Win32系统又适合于16位的Windows的技术,是调用FindWindow()API函数去搜索一个已激活的程序窗口。
Windows API 提供了函数FindWindow,可以是应用程序在启动时检查自己是否已经存在。
该函数在Delphi中的语法为:
function FindWindow(lpClassName: PChar, lpWindowName: PChar): HWND;
其中,参数lpCalssName 是要查找的窗口的类的名称,参数lpWindowName是要查找的窗口的标题(Caption)。
如果找到了相应的窗口实例,将返回一个非0 的该窗口句柄的整型值,否则返回0 。
因此,只要判断应用程序的主窗口(或者伴随着应用程序存在而存在的窗口)是否存在就可以判断是否已经有实例存在了。
例如:
var
hWnd : THandle;
begin
//访止运行多个实例
hWnd:=FindWindow(nil,MainFrmCaption);//搜索窗口 API 在windows单元
if hWnd<>0 then //如果找到指定的窗口
begin
if IsIconic(hWnd) then //如果已被最小化
ShowWindow(hWnd,SW_RESTORE) //则把它恢复
Else //如果窗口被其他窗口遮住,则将它提到前景来
SetForegroundWindow(hWnd);
Halt; //结束本程序
end;
Application.Initialize;
Application.CreateForm(Tdm, dm);
Application.CreateForm(TMainForm, MainForm);
Application.CreateForm(TfrmSettings, frmSettings);
Application.Run;
end.
但是,这种方法有两个缺陷:一是它只能基于窗口类名或标题来搜索窗口,但是在整个系统中窗口很可能会重复。
所以,这样做是不可靠的。
而利用窗口的标题的方法也有问题,因为窗口的标题有可能发生变化(以Delphi和Word为例,每次打开不同文件,它们的标题都会变化),所以这种方法不可取。
另一个缺陷是它每次搜索都要遍历所有窗口,这样执行进来非常慢。
因此,在Win32系统中最好的解决方案是利用那些不依赖于进程的API对象,并且它们的使用也很简单,互斥对象就可以解决这个问题。
当一个应用程序首次运行时,我们就使一个互斥对象被API函数CreateMutex()创建。
这个函数的参数lpName是一个唯一标识互斥对象的字符串。
当应用程序的实例要运行前,它首先要用OpenMutex()来打开互斥对象,如果已经有一个CreateMutex()创建的互斥对象则返回非零值。
另外,当试图运行另一个程序实例时,使第一个实例被激活。
对于这个问题,最好的解决方法是在首次运行时,利用RegisterWindowMessage()函数注册一个消息,并在应用程序中创建唯一的消息标识符。
然后,利用第一个实例对这个消息的响应使它被第二个实例激活。
这种方法阻止新实例的产生,但不能提前,不过较简便。
在Project的Program文件中
program Live;
uses
Windows,
Forms,
ShellApi,
SysUtils,
..;
{$R *.TLB}
{$R *.res}
var
HMutex:Hwnd;
Ret:Integer;
begin
Application.Initialize;
aTitle := 'LiveAuction';
Application.Title := 'LiveAuction';
HMutex:=CreateMutex(nil,False,Pchar(aTitle)); //建立互斥对象,名字为aTitle--'LiveAuction'
Ret:=GetLastError;
If Ret<>ERROR_ALREADY_EXISTS Then
begin
//做我们正常该做的事情
end else
ReleaseMutex(hMutex); //防止创建多个程序实例
Application.Run;
end.
出自/tercel99/article/details/2089352。