别让他们搞砸!限制用户每次只运行一个应用程序

发布日期: FoxTalk 2.0 2006年7月
别让他们搞砸!限制用户每次只运行一个应用程序
作者:Anatoliy Mogylevets   翻译:Sunny
应用:Microsoft Visual FoxPro 8/9
操作系统:Microsoft Windows
 
一看就知道
在某些情况,允许用户在一台机上访问多个应用系统会带来祸患;但你可能会认为阻止用户想做什么是十分困难的。我们将向你展示一些进行限制访问其他应用系统的简单技巧,比你所怀疑的容易的多。
帮助你在你的应用上用最小的努力限制用户使用一个应用系统,我们将:
•描述如何阻止用户当他们正运行一个紧要的应用系统时转到其他任务。
•展示如何使操作系统部件不受未被授权访问。
•讨论微软Windows API的调用,能阻碍用户访问各种各样的程序和操作系统的部件。
•介绍一个VFP类,你可能通过它阻止用户运行其他应用系统。
假设你需要在一个公共区域放置一台电脑:图书馆,银行,言讨会。在这台电脑上面只有一个你想让来访者可以使用的应用系统。不想任何人搞乱这台电脑的设置,在这台机上查邮件,或者浏览互联网。
你可能遇过相似的情形,当这台电脑放在商品区里,只用于一个单独的事情,例如条形码扫描或者输入订单。在这样的情况,你可能会落空,因为一些你的员工玩纸牌游戏和搜索股票的报价花费的时间比做工作还要多。你厌恶小心提防,所以你宁可限制访问微软Windows的开始菜单,我的电脑,浏览器等等。
通过API取消Windows的功能
一种方法——虽然不是最容易的方法——通过Windows API阻止用户打开其他应用系统。Windows的开始按钮是Windows系统托盘的子窗口,它的窗口类是 Shell_TrayWnd。找到任何一个这些窗口的handle,调用ShowWindow或者EnableWindow API函数使它看不见或难以接近。
你可以通过在Windows的注册表里的正确的修改来隐藏任务管理器。你也可以通过创建一个低级的键盘锚(hook)或者调用 RegisterHotKey函数来 阻止按[Alt][Tab]和类似的键盘快捷键。
一个更容易的方法
我们提出一种不同的方法,它足够简单到能只用VFP代码就能够实现的。你大概知道除了默认的Windows桌面外,你可以建立额外的桌面。考虑桌面是最高层窗口主管Windows界面和应用系统窗口。只有默认的Windows桌面响应决定性的快捷键(如[Ctrl][Alt][Delete])和鼠标的右键。只有默认的Windows桌面显示Windows任务栏和开始按钮。
所以,如果你切换到另外一个桌面并在它里面启动一个应用系统,所有上述的访问的问题就会迎韧而解。
AppLauncher,VFP类
我们写了一个简单的VFP类,创建和激活一个新的桌面和在它里面启动一个应用系统。当这个应用系统结束时,它自动地恢复到默认桌面。用这个类创建一个运行器,一个在一个新桌面启动一个可执行文件的应用程序。
另外一个做法是在一个VFP项目里包含这个类。少少几行代码使从这个项目编译成的可执行文件自动地在一个新的桌面里运行。这个类的方法在Listing A里列出,创建和激活一个新桌面。
Listing A: 用来创建和激活一个新桌面的SwitchToNewDesktop方法
PROTECTED PROCEDURE SwitchToNewDesktop
 LOCAL nResult
 THIS.newdesktop = "desktop_" +;
 SUBSTR(SYS(2015), 3)
 THIS.hOrgThread = GetThreadDesktop(;
 GetCurrentThreadId())
 THIS.hOrgInput = OpenInputDesktop(0,0,;
 DESKTOP_SWITCHDESKTOP);
 THIS.hNewDesktop = CreateDesktop(;
 THIS.newdesktop,;
 0,0,0, GENERIC_ALL, 0)
 = SetThreadDesktop(THIS.hNewDesktop)
 nResult = SwitchDesktop(THIS.hNewDesktop)
 IF nResult = 0
 THIS.errorno = GetLastError()
 THIS.message =;
   "SwitchDesktop function failed."
 ENDIF
RETURN (nResult <> 0)
新桌面的名称是唯一的,然而,用一个静态的名称也可以接受的。事实上,检查用于另外一种情形阻止用户在一台电脑上运行重复的应用实例的桌面名称的存在。
一旦这些代码创建新桌面,它 STARTUPINFO结构里 传递这个桌面名称到 CreateProcess API函数。 CreateProcess创建一个新进程和它的主线程。这个新进程在进程调用器的安全上下文里运行指定的可执行的文件。 Listing B 显示了它在类的代码。
Listing B:在分离的桌面里启动一个新进程
oDesktop = CREATEOBJECT("PChar", THIS.newdesktop)
cProcInfo = REPLICATE(CHR(0),16)
cStartInfo = PADR(num2dword(START_INFO_SIZE) +;
 num2dword(0) + num2dword(oDesktop.GetAddr()),;
 START_INFO_SIZE, Chr(0))
IF NOT EMPTY(m.cCommandLine)
 cCommandLine = " " + ALLTRIM(m.cCommandLine)
ENDIF
IF CreateProcess(cApplication, cCommandLine,;
 0,0,0,0,0, m.cStartIn, @cStartInfo,;
 @cProcInfo) <> 0
 THIS.hProcess = buf2dword(;
 SUBSTR(m.cProcInfo, 1,4))
 = WaitForSingleObject(THIS.hProcess,;
 m.nTimeout)
ENDIF
WaitForSingleObject等待进程的结束和把控制交给下一个方法,代码在 Listing C 显示,它恢复默认的桌面。
Listing C: RestoreOrgDesktop方法恢复默认的Windows桌面
PROTECTED PROCEDURE RestoreOrgDesktop
 IF THIS.hOrgInput <> 0
 = CloseDesktop(THIS.hNewDesktop)
 = SwitchDesktop(THIS.hOrgInput)
 = SetThreadDesktop(THIS.hOrgThread)
 = CloseDesktop(THIS.hOrgInput)
 THIS.hOrgInput=0
 ENDIF
测试AppLauncher类
测试的代码在Listing D列出,它在一个新桌面里打开微软件Internet Explore游览器。关闭这个浏览器窗口恢复默认的Windows桌面。
Listing D:在一个新桌面里打开微软件IE游览器的AppLauncher实例
LOCAL obj, ex As Exception
TRY
 obj = NEWOBJECT("AppLauncher",;
 "applauncher.prg")
 WITH obj
 .StartProcessInNewDesktop(;
 "C:/Program Files/Internet Explorer/" +;
 "iexplore.exe",;
 "www.pinpub.com/ME2/Default.asp")
 IF .errorno <> 0
   ? .errorno, .message
 ENDIF
 ENDWITH
CATCH TO ex
 ? ex.ErrorNo, ex.Message
ENDTRY
这些测试代码是十分简单和不言而喻。同样,你可以看到,那个新桌面是实质上干净的。它对鼠标的右键是不起反应的。所有重要的键盘快捷键是失效的。任务管理器不能访问。你可能注意到按下[Ctrl][Alt][Delete]触发一些事情。任务管理器器仍然出现在默认的Windows桌面,但用户不能见到和操作它。
合并我们的类到一个VFP应用里
Listing E 展示了一个合并了 AppLauncher类的VFP应用系统的主程序的样例。这个完全的VFP项目是包含在这篇文章的下载文件里。
Listing E: 主程序在个分隔的桌面果重新启动它的VFP应用系统
PARAMETERS vAnyParameter
IF TYPE("vAnyParameter") = "C"
 WITH _screen
 .WindowState=2
 .Visible=.F.
 ENDWITH
 DO FORM MainForm
 READ EVENTS
ELSE
 DO StartAgain
ENDIF
PROCEDURE StartAgain
 LOCAL oLauncher, ex As Exception
 TRY
 oLauncher = NEWOBJECT("AppLauncher",;
   "AppLauncher.prg")
 WITH oLauncher
   .StartProcessInNewDesktop(;
   _vfp.ServerName, "-r")
*译者注:建议把上面命令的_vfp.ServerName改为sys(16,0),否则编译后的执行文件不能在VFP里直接用DO调用调试。
   IF .errorno <> 0
    ? .errorno, .message
   ENDIF
 ENDWITH
 CATCH TO ex
 = MESSAGEBOX(TRANSFORM(ex.ErrorNo) +;
   ". " + ex.Message + "     ",;
   48, "Error")
 ENDTRY
因为[Ctrl][Alt][Delete]快捷键失效,所以当应用系统变成冻结时,任何情形给用户没有选择,除了关闭计算机。注意:在内存里有同一个应用的两个实例。
第一个实例运行第二个实例并等待它的结束后恢复默认的桌面。这样对于那些要消耗大量内存的VFP应用可能不适当。这种情况,应用系统的运行器实用工具用像C++或Pascal的语言编写更适当。
用C++写AppLauncher实用工具
这篇文章的下载文件包含了一个用C++编写的简单的控制台应用程序。也包含了Visual Studio的Solution文件。Listing F列出了部分C++的代码。要使用这个实用工具,复制AppLauncher.exe到和一个打算在一个分隔的桌面启动的应用系统的同一个目录里。然后创建一个与Figure A所示相似快捷方式或批处理文件。
A:你可以容易地用一个快捷方式实现在一个隔离的桌面启动ApiViewer8.exe应用程序
Listing F: 在隔离的桌面启动一个新进程
void StartProcessInNewDesktop()
{
 SwitchToNewDesktop();
 STARTUPINFO si;
 PROCESS_INFORMATION pi;
 ZeroMemory( &si, sizeof(si) );
 si.cb = sizeof(si);
 si.lpDesktop = newdesktop;
 ZeroMemory( &pi, sizeof(pi) );
 char cmdline1[250];
 strcpy(cmdline1, " ");
 strcat(cmdline1, cmdline);
 if (CreateProcess(appname, cmdline1, NULL, NULL,
 FALSE, 0, NULL, NULL, &si, &pi))
 {
 WaitForSingleObject(pi.hProcess, INFINITE);
 CloseHandle(pi.hProcess);
 CloseHandle(pi.hThread);
 }
 else
 {
 printf("/nCreateProcess failed with err %i/n/n",
   GetLastError());
 usage();
 }
 RestoreOrgDesktop();
}
Anatoliy Mogylevets 是一位在加拿大安大略省Scar区,Visual FoxPro和web开发的独立的顾问,他1990开始开发FoxPro应用程序了。他也是“Using Win32 (WinAPI) Functions in Visual FoxPro” http://www.news2news.com/vfp的所有者。你可以在devicecontext@msn.com联系他。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值