现在的位置: 首页 > 综合 > 正文

一种屏蔽所有系统热键的方法

2013年10月02日 ⁄ 综合 ⁄ 共 6068字 ⁄ 字号 评论关闭

今天在这个网站上看到一篇论述在新建桌面中运行应用程序来屏幕所有系统热键的文章,很受启发,按照它的思路和代码改成了一个 vfp 类,只要直接实例化它并调用它的 run 方法即可在新建桌面中运行一个应用程序。

关于屏蔽系统热键的问题,以前看过很多方法,最好的方法是替换 GINA,但用 vfp 无法实现。这篇文章中的方法可以很容易的修改为几乎所有语言的代码。原理很简单:系统热键(如:ctrl+alt+del, alt+tab, 系统任务栏等)都只会显示在 Windows 的缺省桌面中,所以如果想要使这些东西不出现,最简单的办法就是新建一个桌面(一个全新的桌面,除了背景图片外什么也没有),然后在其中运行它,这样即使你按下系统热键,它也不会在新桌面中显示(它显示在缺省桌面中)。新建和切换桌面只要几个 api 函数即可实现,但切换到新桌面后不能用 run / shellexec 等来启动 exe,因为这些函数只能在缺省桌面中创建新进程,所以需要用到 CreateProcess 这个 api 来创建并启动新进程,它其中的一个结构参数可指定要执行进程所在的桌面。

Run 方法接收两个参数,第一个是要执行的完整文件路径及名称,第二个参数【可选】指定等待它运行多长时间后自动返回缺省桌面,缺省将一直等待到你关闭新桌面中的进程为止,下面是示例代码:

  1. m.oDesktop = NEWOBJECT( 'NewDesktop' )
  2. IF ( 'O' == VARTYPE( m.oDesktop )) AND !ISNULL( m.oDesktop )
  3.   m.cFile = GETFILE( 'exe', '文件名(&N):', '运行(&R)', 0, '请选择要在新桌面中运行的程序' )
  4.   m.oDesktop.Run( m.cFile )
  5. ENDIF
  6. m.oDesktop = NULL
  7. DEFINE CLASS NewDesktop AS Custom
  8.   HIDDEN hOldDesktop
  9.   hOldDesktop = 0
  10.   HIDDEN hOldInput
  11.   hOldInput = 0
  12.   HIDDEN hNewDesktop
  13.   hNewDesktop = 0
  14.   HIDDEN pcNewDesktop
  15.   pcNewDesktop = 0
  16.   HIDDEN NewDesktopName
  17.   NewDesktopName = ('desktop' +SYS(2015))
  18.   HIDDEN ErrMsg
  19.   ErrMsg = ''
  20.   Name = 'NewDesktop'
  21.   HIDDEN PROCEDURE api_decl
  22.     DECLARE Long GetThreadDesktop IN WIN32API Long dwThreadId
  23.     DECLARE Long OpenInputDesktop IN WIN32API ;
  24.       Long dwFlags, Long fInherit, Long dwDesiredAccess
  25.     DECLARE Long CreateDesktop IN WIN32API ;
  26.       String lpszDesktop, Long lpszDevice, Long pDevmode, ;
  27.       Long dwFlags, Long dwDesiredAccess, Long lpsa
  28.     DECLARE Long SetThreadDesktop IN WIN32API Long hDesktop
  29.     DECLARE Long SwitchDesktop IN WIN32API Long hDesktop
  30.     DECLARE Long CloseDesktop IN WIN32API Long hDesktop
  31.     DECLARE Long CreateProcess IN WIN32API ;
  32.       String pszAppName, String pszCmdLine, ;
  33.       Long lpProcessAttr, Long lpThreadAttr, ;
  34.       Long bInheritHandles, Long dwCreationFlags, ;
  35.       Long lpEnvironment, String pszCurDir, ;
  36.       String lpStartupInfo, String @ lpProcInfo
  37.     DECLARE Long CloseHandle IN WIN32API Long hObject
  38.     DECLARE Long WaitForSingleObject IN WIN32API ;
  39.       Long hHandle, Long dwMilliseconds
  40.     DECLARE Long GetProcessHeap IN WIN32API
  41.     DECLARE Long HeapAlloc IN WIN32API ;
  42.       Long hHeap, Long dwFlags, Long dwBytes
  43.     DECLARE Long HeapFree IN WIN32API ;
  44.       Long hHeap, Long dwFlags, Long lpMem
  45.     DECLARE Long GetLastError IN WIN32API
  46.     This.pcNewDesktop = HeapAlloc( GetProcessHeap(), 8, LEN(This.NewDesktopName)+1 )
  47.     IF ( 0 == This.pcNewDesktop )
  48.       MESSAGEBOX( '内存分配失败 !', 16, '错误' )
  49.     ELSE
  50.       SYS( 2600, This.pcNewDesktop, LEN(This.NewDesktopName), This.NewDesktopName )
  51.     ENDIF
  52.   ENDPROC
  53.   PROCEDURE Run
  54.     *!*  ------------------------------------------------------------------------
  55.     *!*  功能: 在新建桌面中运行指定的程序
  56.     *!*  入口: tcExeFile - 要执行的 exe 文件
  57.     *!*      tiTimeout - 等待执行时间(单位 ms, 0 代表一直等待到它终止并退出)
  58.     *!*  ------------------------------------------------------------------------
  59.     LPARAMETERS tcExeFile, tiTimeout
  60.     IF ( 'C' != VARTYPE( m.tcExeFile )) OR EMPTY( m.tcExeFile )
  61.       RETURN .F.
  62.     ENDIF
  63.     IF ( PCOUNT() < 2 ) OR ( 'N' != VARTYPE( m.tiTimeout )) OR ( m.tiTimeout <= 0 )
  64.       m.tiTimeout = -1
  65.     ENDIF
  66.     This.ErrMsg = ''
  67.     IF This.SwitchToNewDesktop()
  68.       This.StartProcess( m.tcExeFile, m.tiTimeout )
  69.     ENDIF
  70.     IF !EMPTY( This.ErrMsg )
  71.       MESSAGEBOX( This.ErrMsg, 16, '错误' )
  72.     ENDIF
  73.   ENDPROC
  74.   HIDDEN PROCEDURE SwitchToNewDesktop
  75.     #define DESKTOP_SWITCHDESKTOP       0x0100
  76.     #define GENERIC_ALL                 0x10000000
  77.     *!* 保存当前线程所在的桌面句柄
  78.     This.hOldDesktop = GetThreadDesktop( _vfp.ThreadId )
  79.     *!* 保存当前用户输入线程的桌面句柄
  80.     This.hOldInput = OpenInputDesktop( 0, 0, DESKTOP_SWITCHDESKTOP )
  81.     *!* 创建新桌面
  82.     This.hNewDesktop = CreateDesktop( This.NewDesktopName, 0, 0, 0, GENERIC_ALL, 0 )
  83.     IF ( 0 == This.hNewDesktop )
  84.       This.ErrMsg = '创建桌面失败!错误代码: ' + TRANSFORM( GetLastError())
  85.       RETURN .F.
  86.     ENDIF
  87.     *!* 切换当前线程到新建桌面中
  88.     SetThreadDesktop( This.hNewDesktop )
  89.     IF ( 0 == SwitchDesktop( This.hNewDesktop ))
  90.       This.ErrMsg = '切换桌面失败!错误代码: ' + TRANSFORM( GetLastError())
  91.       RETURN .F.
  92.     ENDIF
  93.   ENDPROC
  94.   HIDDEN PROCEDURE StartProcess
  95.     LPARAMETERS tcExeFile, tiTimeout
  96.     
  97.     *!*  typedef struct _PROCESS_INFORMATION {
  98.     *!*    HANDLE hProcess;
  99.     *!*    HANDLE hThread;
  100.     *!*    DWORD dwProcessId;
  101.     *!*    DWORD dwThreadId;
  102.     *!*  } PROCESS_INFORMATION
  103.     *!*  typedef struct _STARTUPINFO {
  104.     *!*    DWORD cb;
  105.     *!*    LPTSTR lpReserved;
  106.     *!*    LPTSTR lpDesktop;
  107.     *!*    LPTSTR lpTitle;
  108.     *!*    DWORD dwX;
  109.     *!*    DWORD dwY;
  110.     *!*    DWORD dwXSize;
  111.     *!*    DWORD dwYSize;
  112.     *!*    DWORD dwXCountChars;
  113.     *!*    DWORD dwYCountChars;
  114.     *!*    DWORD dwFillAttribute;
  115.     *!*    DWORD dwFlags;
  116.     *!*    WORD wShowWindow;
  117.     *!*    WORD cbReserved2;
  118.     *!*    LPBYTE lpReserved2;
  119.     *!*    HANDLE hStdInput;
  120.     *!*    HANDLE hStdOutput;
  121.     *!*    HANDLE hStdError;
  122.     *!*  } STARTUPINFO
  123.     LOCAL cSI, cPI, hProcess
  124.       
  125.     IF ( m.tiTimeout <= 0 )
  126.       m.tiTimeout = -1
  127.     ENDIF
  128.       
  129.     m.cSI = BINTOC( 0, 'rs' ) ;
  130.       + BINTOC( This.pcNewDesktop, 'rs' ) + REPLICATE( CHR(0), 14*4 )
  131.     m.cSI = BINTOC( LEN( m.cSI )+4, 'rs' ) + m.cSI
  132.     m.cPI = REPLICATE( CHR(0), 4*4 )
  133.     IF ( 0 == CreateProcess( ;
  134.       m.tcExeFile, '', 0, 0, 0, 0, 0, NULL, m.cSI, @ m.cPI ))
  135.       This.ErrMsg = '在新桌面中创建进程失败! 错误代码: ' + TRANSFORM( GetLastError())
  136.     ELSE
  137.       m.hProcess = CTOBIN( LEFT( m.cPI, 4 ), 'rs' )
  138.       *!* 等待此进程终止
  139.       WaitForSingleObject( m.hProcess, m.tiTimeout )
  140.       *!* CloseHandle( m.hProcess )
  141.     ENDIF
  142.     This.ClearUp()
  143.   ENDPROC
  144.   HIDDEN PROCEDURE ClearUp
  145.     IF ( 0 != This.hOldInput )
  146.       SwitchDesktop( This.hOldInput )        && 切换回默认桌面
  147.       This.hOldInput = 0
  148.     ENDIF
  149.     IF ( 0 != This.hOldDesktop )
  150.       SetThreadDesktop( This.hOldDesktop )   && 回复原线程桌面
  151.       This.hOldDesktop = 0
  152.     ENDIF
  153.     IF ( 0 != This.hNewDesktop )
  154.       CloseDesktop( This.hNewDesktop )       && 关闭新建的桌面
  155.       This.hNewDesktop = 0
  156.     ENDIF
  157.   ENDPROC
  158.   PROCEDURE Init
  159.     This.api_decl()
  160.   ENDPROC
  161.   PROCEDURE Destroy
  162.     IF ( 0 != This.pcNewDesktop )
  163.       HeapFree( GetProcessHeap(), 0, This.pcNewDesktop )
  164.       This.pcNewDesktop = 0
  165.     ENDIF
  166.   ENDPROC
  167. ENDDEFINE

进一步的,我们可以检查并限制我们的程序只能在新桌面中运行,这样可以最大程度的保护它的运行不受用户切换任务的干扰。

 

抱歉!评论已关闭.