




全文预览已结束
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
公司开发的软件需要对串口进行*作,每次打开软件后程序自动去打开串口寻找连接到串口上的设备,但是如果用户不知道打开了两次,那么第二次打开的程序是不能正常使用的,因为对串口的*作时独占的,第一个程序独占了串口的使用权,其他程序无法再使用那一个串口,当然如果PC机器上有两个串口,那第二个程序也是可以用的。为了解决这个问题,必须限制对串口*作的软件只能打开一个。打开软件后用户如果误*作再次想打开该软件,需要提示用户软件已经打开,并让已打开的软件显示在窗口最顶层。 下面是Delphi版的解决方法。(方法一)利用互斥对象开发过多线程软件的可能都使用过互斥对象,它常被用做线程间同步的技术手段。简要的提一下互斥对象:互斥对象把第一次建立它的程序作为主程序,这样只用检测互斥对象是否已经有主程序就判断程序是否已经运行过,这里需要涉及到一个api函数:WaitForSingleObject,该函数的第一个参数为用以检测的互斥对象,第2个参数的表示函数返回结果前的滞留时间,如果改函数返回wait_TimeOut就表明互斥对象已经有了一个主程序。注意:以下的代码都出现在工程文件中,而不是单元文件中。var myMutex:HWND;begin /CreateMutex建立互斥对象,并且给互斥对象起一个唯一的名字。 myMutex:=CreateMutex(nil,false,hkOneCopy); /程序没有被运行过 if WaitForSingleObject(myMutex,0)wait_TimeOut then begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; End;End;注释:当应用程序第一次运行的时候,在应用程序中会建立一个互斥对象,名称为hkOneCopy,然后判断系统中有没有这个互斥对象,如果没有则初始化应用程序。下面再完善一下这个程序。我们不希望程序被多次运行,而是希望如果程序运行过后,再运行这个程序的时候,将已运行的程序做出一些响应,比如说让它变为最上层的活动窗口来提示用户该程序正在运行。为达到这个目的,必须要获得正在运行程序的句柄,然后用一个APISetForeGroundWindow(handle),来使程序的窗口最前并激活。为了得到程序的句柄,要使用windows枚举函数EnumWindows来遍历windows窗口列表,该函数需要一个回调函数作参数,用这个回调函数来对每一个系统中的窗口进行调用直到最后一个窗口或回调函数返回false为止注:关于EnumWindows函数的介绍在篇尾。只要编写这个回调函数并在其中不断的比较当前遍历到的窗口类名和我们的程序的主窗口类名,以及比较窗口可执行文件的名称和我们程序的名称直到找到相同的为止,将这时的窗口句柄保存下来就行了。为获得窗口的类名和句柄,需要一个APIGetClassName,为获得可执行文件的名称,需要APIGetModuleFileName。下面是详细代码。注意:下面代码在delphi7下运行通过。但是如果窗口最小化后,再次运行程序时,原先已经运行的程序能够被置前并激活但是标题栏的最小化按钮却不能用了。当尝试了N中方法后估计是delphi自身TForm类的问题,下面给出一个解决方案:在窗口上放一个ApplicationEvents控件,它管理着应用程序所有的消息。我们在它的OnMessage事件里写上下面的代码: if Msg.hwnd=Form1.Handle then begin/161 是在标题栏按下鼠标/8 是在标题栏的最小化按钮上按下鼠标 if (Msg.message= 161) and (msg.wParam= 8) then begin Form1.WindowState:= wsMinimized; end; end; program MyThreadTest;uses Windows,Forms, SysUtils, Messages, Dialogs, Unit1 in Unit1.pas Form1,$R *.resvar myMutex, FindHid: HWND; MoudleName: string;function EnumWndProc(hwnd: Thandle; param: Cardinal): bool; stdcall;/由于用于api回调函数,请使用windows传统的参数传递方式stdcallvar ClassName, WinMoudleName: string; WinInstance: THandle;begin result := true; SetLength(ClassName, 100); GetClassName(hwnd, pchar(ClassName), length(ClassName); /获得当前遍历窗口的类名 ClassName := pchar(ClassName); /在字符串后加结束符,确定字符串结束 if UpperCase(ClassName) = UpperCase(TForm1.ClassName) then /比较类名 begin WinInstance := GetWindowLong(hwnd, GWL_HINSTANCE); /获得当前遍历窗口的实例 setlength(WinMoudleName, 100); /获得当前遍历窗口的程序文件名 GetModuleFileName(WinInstance, pchar(WinMoudleName), length(WinMoudleName); WinMoudleName := pchar(WinMoudleName); WinMoudleName :=ExtractFileName(WinMoudleName); /MoudleName为工程全局变量,自身程序的文件名 if UpperCase(WinMoudleName) = UpperCase(MoudleName) then begin FindHid := hwnd;/FindHid为工程全局变量保存找到的句炳 result := false; /找到以后就结束遍历 end; end;end;begin / CreateMutex建立互斥对象,并且给互斥对象起一个唯一的名字 myMutex := CreateMutex(nil, false, hkOneCopy); if WaitForSingleObject(myMutex, 0) wait_TimeOut then /程序没有被运行过 begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end else begin SetLength(MoudleName, 100); /获得自己程序文件名 GetModuleFileName(HInstance, pchar(MoudleName), length(MoudleName); MoudleName := pchar(MoudleName); MoudleName := ExtractFileName(MoudleName); EnumWindows(EnumWndProc, 0); /调用枚举函数 if FindHid 0 then begin ShowWindow(FindHid,SW_RESTORE); SetForegroundWindow(FindHid); end; end;end.EnumWindows函数使用:EnumWindows 用来列举屏幕上所有顶层窗口。MSDN:The EnumWindows function enumerates all top-level windows on the screen by passing the handle to each window。函数形式:BOOL EnumWindows(WNDENUMPROC lpEnumFunc, /callback function LPARAM lParam); /application-defined value其中 WNDENUMPROC 是回调函数,回调函数中写自己想做的*作,当调用EnumWindows的时候,每次遇到一个窗口,系统就调用一次你的WNDENUMPROC ,然后把窗口句柄传给你。EnumWindows 函数成功则返回非0值; 函数失败则返回0值; EnumWindowsProc 返回0值,同样导致函数EnumWindows 返回0值。 另外,该函数不列举子窗口,除了几种拥有WS_CHILD 风格的系统所属窗口。MSDN:The EnumWindows function does not enumerate child windows,with the exception of a few top-level windows owned by the system that have the WS_CHILD style. 使用举例:先声明一个EnumWindowsProc ,比如:BOOL CALLBACK EnumWindowsProc_1(HWND hwnd,LPARAM lparam) ;然后实现此函数,写入自己想做的事情,比如:BOOL CALLBACK EnumWindowsProc_1(HWND hwnd,LPARAM lparam) char lpWinTitle256; :GetWindowText(hwnd,lpWinTitle,256-1); CString m_strTitle; m_strTitle.Format(%s,lpWinTitle); if(m_strTitle.Find(Internet Explorer)!=-1) AfxMessageBox(这是一个IE窗口!) ; return TRUE ;然后就可以在其他地方调用EnumWindows的时候使用回调函数,比如::EnumWindows(EnumWindowsProc_1,0) ;这样每当遇到IE窗口时,就会进行 提示“这是一个IE窗口!” 的*作。方法二:不用互斥对象。我们可以利用向系统添加全局原子的方法,来防止多个程序实例的运行。全局原子由Windows 系统负责维持,它能保证其中的每个原子都是唯一的,管理其引用计数,并且当该全局原子的引用计数为0时,从内存中清除。我们用GlobalAddAtom 函数向全局原子添加一个255个字节以内的字符串,用GlobalFindAtom来检查是否已经存在该全局原子,最后在程序结束时用GlobalDeleteAtom函数删除添加的全局原子。示例如下: Uses Windows const iAtom=SingleApp; begin if GlobalFindAtom(iAtom)=0 then begin GlobalAddAtom(iAtom); Application.Initialize; Application.CreateForm(TForm1,Form1); Application.Run; GlobalDeleteAtom(GlobalFindAtom(iAtom); end else Me
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 民转幼儿园后勤工作总结与纸尿裤售后培训
- 关于名人的爱情故事
- 2026届内蒙古呼伦贝尔市九年级化学第一学期期末学业水平测试模拟试题含解析
- 街道亮点工作总结
- 2026届重庆市南开融侨中学九年级化学第一学期期末复习检测试题含解析
- 研发中心年终总结报告
- 浙江省宁波市鄞州区七校2026届九年级英语第一学期期末学业质量监测试题含解析
- 重庆綦江南川巴县2026届化学九年级第一学期期中综合测试模拟试题含解析
- 2026届江西省育华学校九年级英语第一学期期末达标检测模拟试题含解析
- 山东省淄博市沂源县第二中学2024-2025学年高二上学期11月期中考试政治试卷(含答案)
- 2025年度哈尔滨市平房区纪委监委公开招聘雇员2人考试参考题库及答案解析
- 2025年江西省高考化学试卷真题(含答案)
- 情绪管理课2025年职场压力释放与心灵成长分析报告
- 2025年征地拆迁考试题及答案
- 巡游出租车考试题及答案
- 2025年秋季学期人教版三年级上册数学教学计划含教学进度表(三篇)
- 2025至2030中国方竹笋市场经营方向与竞争格局分析报告
- 2025年人教版三年级数学上册《混合运算》教案
- 2025医用眼科器械消毒处理标准流程
- 胸部穿刺教学课件
- 2025-2026学年苏教版(2024)小学科学三年级上册(全册)课时练习及答案(附目录P102)
评论
0/150
提交评论