Products Purchase Publishing Articles Support Company Contact |
Articles > COM > Block Application Loading |
|||||
.NET COM
|
Block Selected Applications from LoadingOur customers sometimes ask for the ability to prevent users from starting certain applications. There is no generic way to do so in Windows. While you can use SpyWorks to prevent particular applications (such as File Explorer) from launching programs, there are so many different ways to do this (such as the Run item in the Start menu, or creating a VB program that shells the desired application) that it quickly becomes a Herculean task. There are even ways to start programs beyond SpyWorks' ability to influence, such as the Command Prompt. However, it is possible to detect when a program has started and then close it down right away. We will use two features of SpyWorks: the WinHook control and the sample code for getting information about currently running processes. The WinHook control has the ability to detect messages on a system-wide basis. By detecting the WM_CREATE message, we can tell whenever a new window has been created. When such an event takes place, we can use the process functions to determine the application filename that the window belongs to. With a few API function calls, we can then shut down the offending application. Here is the fully commented VB6 sample code for such a utility. This technique will also work in Visual Studio .NET (with minor code changes). Simply create a form containing a SpyWorks WinHook control and a textbox named "Text1". The textbox contains the name of the application you do not want the user to start (such as "notepad.exe"). Copy the code and place it in the code window of the form. This kind of program is most useful if it starts the moment the user has logged in. You can do that by adding a new item to the Registry. In the key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run Add a new string value with the application title as the value name and the full path location of the application as the value data. Be very careful when modifying the Registry. The command prompt is not a normal window, and you will not get any WM_CREATE message when it is launched. If you want to block it, you will need to periodically poll the list of running programs (using the full suite of task listing functions from the SpyWorks samples), and then use TerminateProcess on it when you see "cmd.exe" in the list. Option Explicit Private Const MAX_PATH As Long = 260 ' for OpenProcess Private Const PROCESS_VM_READ As Long = &H10& Private Const PROCESS_QUERY_INFORMATION As Long = &H400& Private Const PROCESS_TERMINATE As Long = &H1& ' Messages Private Const WM_CLOSE As Long = &H10& Private Const WM_CREATE As Long = &H1& ' General function declarations Private Declare Function GetVersion Lib "kernel32" () As Long Private Declare Function GetWindowThreadProcessId Lib "user32" _ (ByVal hwnd As Long, lpdwProcessId As Long) As Long Private Declare Function OpenProcess Lib "kernel32" _ (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _ ByVal dwProcessId As Long) As Long Private Declare Function GetParent Lib "user32" _ (ByVal hwnd As Long) As Long Private Declare Function GetClassName Lib "user32" Alias _ "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName _ As String, ByVal nMaxCount As Long) As Long Private Declare Function SendMessage Lib "user32" Alias _ "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _ ByVal wParam As Long, lParam As Long) As Long Private Declare Function TerminateProcess Lib "kernel32" _ (ByVal hProcess As Long, ByVal uExitCode As Long) As Long Private Declare Function CloseHandle Lib "kernel32" _ (ByVal hObject As Long) As Long ' WinNT, 2000, XP specific function declarations. Samples using ' a full set of these functions is a part of SpyWorks, including ' a complete task monitoring application. Private Declare Function EnumProcessModules Lib "psapi.dll" _ (ByVal hProcess As Long, lphModule As Long, ByVal cb As Long, _ lpcbNeeded As Long) As Long Private Declare Function GetModuleBaseNameA Lib "psapi.dll" _ (ByVal hProcess As Long, ByVal hModule As Long, ByVal _ lpBaseName As String, ByVal nSize As Long) As Long ' Win95, Win98, WinME specific function declarations. Samples ' using a full set of these functions is a part of SpyWorks, ' including a complete task monitoring application. Private Const TH32CS_SNAPPROCESS = &H2 Private Type PROCESSENTRY32 dwSize As Long cntUsage As Long th32ProcessID As Long th32DefaultHeapID As Long th32ModuleID As Long cntThreads As Long th32ParentProcessID As Long pcPriClassBase As Long dwFlags As Long szExeFile As String * MAX_PATH End Type Private Declare Function CreateToolhelp32Snapshot& Lib _ "kernel32" (ByVal dwFlags As Long, ByVal th32ProcessID As Long) Private Declare Function Process32First& Lib "kernel32" _ (ByVal hSnapShot As Long, lppe As PROCESSENTRY32) Private Declare Function Process32Next& Lib "kernel32" _ (ByVal hSnapShot As Long, lppe As PROCESSENTRY32) Private Sub Form_Load() ' Set up the hook control. This can all be done in the design ' time property window, but it is done here for clarity. WinHook1.Messages = WM_CREATE WinHook1.HookType = shkCallWndProc WinHook1.Monitor = shkEntireSystem WinHook1.Notify = shkPosted WinHook1.HookEnabled = True End Sub Private Sub WinHook1_WndMessage(wnd As Long, msg As Long, _ wp As Long, lp As Long, nodef As Integer) Dim RetVal As Long Dim hProcess As Long Dim ProcessName As String Dim ProcessID As Long Dim ClassName As String ' Get the ProcessID for the newly created window RetVal = GetWindowThreadProcessId(wnd, ProcessID) ' Get the filename of the process using the correct method ' depending on which operating system we are running. If (OSIs95Based() = True) Then ProcessName = GetProcessName95(ProcessID) Else ' Open the process so we can get access to its information. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION _ Or PROCESS_VM_READ, False, ProcessID) If (hProcess = 0) Then Debug.Print "We cannot gain access to the process" Exit Sub End If ProcessName = GetProcessNameNT(hProcess) RetVal = CloseHandle(hProcess) ' Don't forget this End If ' You can keep a record of newly created windows. ' You cannot create new forms or put up a message ' box inside the WndMessage event - if you want to ' notify the user the reason they cannot start the ' application, try using a Timer control. Put it on ' on the form, but in a disabled state. Enable it ' here. In the Timer event, put up whatever message ' you need and then disable the Timer again. ' Debug.Print "Proc ID:" & Hex$(ProcessID) & " " & _ ProcessName & " created window " & Hex$(wnd) ' See if this program is the one we want to close. ' If not, exit. If (StrComp(ProcessName, Text1.Text, vbTextCompare) <> 0) Then Exit Sub End If ' Check to see if this is a top level window - if it ' has no parent, then it is one. Child windows do not ' concern us. If (GetParent(wnd) = 0) Then ' Check the classname to see if it is a top level window ' injected by SpyWorks - we ignore those. ClassName = String$(30, 0) RetVal = GetClassName(wnd, ClassName, Len(ClassName)) ClassName = Left$(ClassName, 17) If (ClassName = "dwXferWindowClass") Then ' This is a top level window from SpyWorks - ignore it Exit Sub End If ' It is a real top level window -> try closing it. Closing ' it is done in the DelayedEvent. We pass the window ' handle as the parameter because we will need it in the ' DelayedEvent. WinHook1.PostEvent = wnd End If Debug.Print Hex$(wnd), ProcessName, Hex$(GetParent(wnd)) End Sub Private Sub WinHook1_DelayedEvent(lvalue As Long) ' This event is firing a short time after the WndMessage ' is over. We set this event into motion by setting the ' "PostEvent" property of the WinHook1 control below. The ' value we set the property to is passed as the "lvalue" ' here. We need to use a delay because it is not good ' practice to send messages (or call API functions that ' send messages) inside the WndMessage event (it can cause ' unpredictable behavior, even crashes). Dim RetVal As Long ' We will be nice and try to close the program by sending ' it a "WM_CLOSE" message. This is prefered because it ' allows the application to clean up correctly. RetVal = SendMessage(lvalue, WM_CLOSE, 0, 0) ' This should work on most applications. A less nice way ' of closing another application is TerminateProcess. The ' problem with this is that the application will leave ' allocated memory and resources behind without freeing them. ' To use this, we will need to open the Process with the ' correct flags. ' Dim ExitCode as long ' Dim hProcess as long ' RetVal = GetWindowThreadProcessId(lvalue, ProcessID) ' hProcess = OpenProcess(PROCESS_TERMINATE, False, ProcessID) ' If (hProcess = 0) Then ' Debug.Print "We cannot gain access to the process" ' Exit Sub ' End If ' RetVal = TerminateProcess(hProcess, ExitCode) ' RetVal = CloseHandle(hProcess) ' Don't forget this End Sub Private Function GetProcessName95(ByVal ProcessID As Long) _ As String ' For Windows 95-type operating systems, we will use the ' built in TOOLHELP32 functions. This is a little tricky - ' there is no direct way from a hProcess to a filename. We ' need to loop through all the running processes and get the ' name of the one that matches the parameter. Dim RetVal As Long Dim ModuleFileName As String Dim ModuleBaseName As String Dim ProcessName As String Dim CanLoop As Boolean Dim hSnapShotProc As Long Dim ProcessEntry As PROCESSENTRY32 ' Init some variables ProcessName = "" ' Get a snapshot of the processes currently running ' on the system hSnapShotProc = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) ProcessEntry.dwSize = LenB(ProcessEntry) ' Loop through all the processes in the snapshot RetVal = Process32First(hSnapShotProc, ProcessEntry) Do ' If the ProcessID's match.. If (ProcessEntry.th32ProcessID = ProcessID) Then ' Get the process name from the path supplied ProcessName = ProcessEntry.szExeFile ProcessName = Left$(ProcessName, _ InStr(ProcessName, Chr$(0)) - 1) While (InStr(ProcessName, "\") > 0) ProcessName = Right(ProcessName, _ Len(ProcessName) - InStr(ProcessName, "\")) Wend GoTo CleanUp End If Loop While (Process32Next(hSnapShotProc, ProcessEntry) _ <> False) CleanUp: RetVal = CloseHandle(hSnapShotProc) GetProcessName95 = ProcessName End Function Private Function GetProcessNameNT(ByVal hProcess As Long) As String ' For Windows NT, we will need to use the PSAPI.DLL functions. ' This file should be included in Windows 2000 and XP. It ' will need to be obtained and copied into the System32 ' directory on Windows NT 3.51 machines, but the file is ' commonly available. Dim RetVal As Long Dim cbNeeded As Long Dim hmod As Long Dim ProcessName As String Dim ProcName As String Dim ProcessID As Long RetVal = EnumProcessModules(hProcess, hmod, _ LenB(hmod), cbNeeded) ProcName = String$(MAX_PATH, 0) RetVal = GetModuleBaseNameA(hProcess, hmod, ProcName, _ LenB(ProcName)) ProcessName = Left$(ProcName, InStr(ProcName, Chr$(0)) - 1) GetProcessNameNT = ProcessName End Function Private Function OSIs95Based() As Boolean OSIs95Based = GetVersion() And &H80000000 End Function
For notification when new articles are available, sign up for Desaware's Newsletter. |
|
|||
Products Purchase Articles Support Company Contact Copyright© 2012 Desaware, Inc. All Rights Reserved. Privacy Policy |
|||||