|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic Win32 Shell
Routines Undocumented Windows: Shell Dialogs Shutdown, Run and Restart Dialogs |
||
Posted: | Wednesday August 6, 1997 | |
Updated: | Monday December 26, 2011 | |
Applies to: | VB4-32, VB5, VB6 | |
Developed with: | VB4-32, Windows 95 | |
OS restrictions: | None | |
Author: | Brad Martinez | |
Related: |
SHChangeNotifyRegister: Receive Shell Change Notifications Undocumented Windows: Overview Undocumented Windows: Format Disk Dialog Undocumented Windows: Change Icon Dialog Undocumented Windows: Path Functions |
|
Prerequisites | |||||||||||||||||||||||||||||||||||
None. | |||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||
This
is our first venture into the realms of the undocumented, thanks to code provided to VBnet by Brad Martinez. On this page, we'll
discover how to call the Shutdown Windows Dialog, the Run Programs dialog (just like the Start menu / Run command), and how to invoke the
Windows messagebox requesting the user restart windows to effect a system change.
The three APIs detailed here are, of course, the infamous #59, #60 and #61! Defined in Shell32 simply as ordinal numbers, and undocumented by Microsoft, these APIs are part of the background support to Windows itself, and coincidentally, now that we've found them, offer several interesting functions that we can use as well. Of course, a strong caveat applies: as undocumented APIs, they are not supported in any way, shape or form by Microsoft. In fact, care should be taken in using these, as there is no guarantee that they will reside at the same ordinal position, if at all, in future versions of Windows. But for the API-inclined, the chance to play with them can be enough, imagining what other undocumented treasures remain concealed. In Shell32, the three APIs of interest are defined as:
For a more detailed description of the meaning of these params, and
the names, see the Windows by the Numbers Overview. |
|||||||||||||||||||||||||||||||||||
BAS Module Code | |||||||||||||||||||||||||||||||||||
Paste the following into the general declarations area of a file you name StringUtils.bas: | |||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'Set to True if the current OS is WinNT. 'Tested in *every* shell function's proc via 'a call to CheckString. Public bIsWinNT As Boolean '------------------------------------------------------ Public Declare Function GetVersionEx Lib "kernel32" _ Alias "GetVersionExA" _ (lpVersionInformation As OSVERSIONINFO) As Long Public Type OSVERSIONINFO dwOSVersionInfoSize As Long dwMajorVersion As Long dwMinorVersion As Long dwBuildNumber As Long dwPlatformId As Long szCSDVersion As String * 128 End Type Public Const VER_PLATFORM_WIN32s = 0 Public Const VER_PLATFORM_WIN32_WINDOWS = 1 Public Const VER_PLATFORM_WIN32_NT = 2 'Handles overlapped source and 'destination blocks Public Declare Sub CopyMemory Lib "kernel32" _ Alias "RtlMoveMemory" _ (pDest As Any, _ pSource As Any, _ ByVal ByteLen As Long) Public Declare Function IsTextUnicode Lib "advapi32" _ (lpBuffer As Any, _ ByVal cb As Long, _ lpi As Long) As Long Public Const IS_TEXT_UNICODE_ASCII16 = &H1 Public Const IS_TEXT_UNICODE_REVERSE_ASCII16 = &H10 Public Const IS_TEXT_UNICODE_STATISTICS = &H2 Public Const IS_TEXT_UNICODE_REVERSE_STATISTICS = &H20 Public Const IS_TEXT_UNICODE_CONTROLS = &H4 Public Const IS_TEXT_UNICODE_REVERSE_CONTROLS = &H40 Public Const IS_TEXT_UNICODE_SIGNATURE = &H8 Public Const IS_TEXT_UNICODE_REVERSE_SIGNATURE = &H80 Public Const IS_TEXT_UNICODE_ILLEGAL_CHARS = &H100 Public Const IS_TEXT_UNICODE_ODD_LENGTH = &H200 Public Const IS_TEXT_UNICODE_DBCS_LEADBYTE = &H400 Public Const IS_TEXT_UNICODE_NULL_BYTES = &H1000 Public Const IS_TEXT_UNICODE_UNICODE_MASK = &HF Public Const IS_TEXT_UNICODE_REVERSE_MASK = &HF0 Public Const IS_TEXT_UNICODE_NOT_UNICODE_MASK = &HF00 Public Const IS_TEXT_UNICODE_NOT_ASCII_MASK = &HF000 Public Function IsWinNT() As Boolean 'Returns True if the current operating system is WinNT Dim osvi As OSVERSIONINFO osvi.dwOSVersionInfoSize = Len(osvi) GetVersionEx osvi IsWinNT = (osvi.dwPlatformId = VER_PLATFORM_WIN32_NT) End Function Public Function CheckString(msg As String) As String If bIsWinNT Then CheckString = StrConv(msg, vbUnicode) Else CheckString = msg End If End Function Public Function GetStrFromPtr(lpszStr As Long, nBytes As Integer) As String 'Returns string before first null char 'encountered (if any) from a string pointer. 'lpszStr = memory address of first byte in string 'nBytes = number of bytes to copy. 'StrConv used for both ANSII and Unicode strings 'BE CAREFUL! ReDim ab(nBytes) As Byte 'zero-based (nBytes + 1 elements) CopyMemory ab(0), ByVal lpszStr, nBytes GetStrFromPtr = GetStrFromBuffer(StrConv(ab(), vbUnicode)) End Function Public Function GetStrFromBuffer(szStr As String) As String 'Returns string before first null char encountered (if any) 'from either an ANSII or Unicode string buffer. If IsUnicodeStr(szStr) Then szStr = StrConv(szStr, vbFromUnicode) If InStr(szStr, vbNullChar) Then GetStrFromBuffer = Left$(szStr, InStr(szStr, vbNullChar) - 1) Else GetStrFromBuffer = szStr End If End Function Public Function IsUnicodeStr(sBuffer As String) As Boolean 'Returns True if sBuffer evaluates to a Unicode string Dim dwRtnFlags As Long dwRtnFlags = IS_TEXT_UNICODE_UNICODE_MASK IsUnicodeStr = IsTextUnicode(ByVal sBuffer, Len(sBuffer), dwRtnFlags) End Function |
|||||||||||||||||||||||||||||||||||
BAS Module Code | |||||||||||||||||||||||||||||||||||
Add a second BAS module, and paste the following into the general declarations area of a file you name UndocShellDialogDefs.bas: | |||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||
Option Explicit '------------------------------------------------------ 'The "System Settings Change" message box. '("You must restart your computer before the new 'settings will take effect.") Public Declare Function SHRestartSystemMB Lib "shell32" _ Alias "#59" _ (ByVal hOwner As Long, _ ByVal sExtraPrompt As String, _ ByVal uFlags As Long) As Long 'hOwner = Message box owner, specify 0 'for desktop (will be top-level). 'sPrompt = Specified prompt string placed 'above the default prompt. 'uFlags = Can be the following values: 'WinNT 'Appears to use ExitWindowsEx uFlags values 'and behave accordingly: Public Const EWX_LOGOFF = 0 'NT:needs SE_SHUTDOWN_NAME priv (no def prompt) Public Const EWX_SHUTDOWN = 1 Public Const EWX_REBOOT = 2 Public Const EWX_FORCE = 4 Public Const EWX_POWEROFF = 8 'Win95/98 'Any Yes selection produces the equivalent to 'ExitWindowsEx(EWX_FORCE, 0) (?) '(i.e. no WM_QUERYENDSESSION or WM_ENDSESSION is sent!). 'Other than is noted below, it was found that any other 'value shuts the system down (no reboot) and includes 'the default prompt. 'Shuts the system down (no reboot) and does not include 'the default prompt: Public Const shrsExitNoDefPrompt = 1 'Reboots the system and includes the 'default prompt. Public Const shrsRebootSystem = 2 '= EWX_REBOOT 'Rtn vals: Yes = 6 (vbYes), No = 7 (vbNo) 'The Shut Down dialog via the Start menu Public Declare Function SHShutDownDialog Lib "shell32" _ Alias "#60" _ (ByVal YourGuess As Long) As Long 'The Run dialog via the Start menu Public Declare Function SHRunDialog Lib "shell32" _ Alias "#61" _ (ByVal hOwner As Long, _ ByVal Unknown1 As Long, _ ByVal Unknown2 As Long, _ ByVal szTitle As String, _ ByVal szPrompt As String, _ ByVal uFlags As Long) As Long 'hOwner = Dialog owner, specify 0 for desktop '(will be top-level) 'Unknown1 = ? 'Unknown2 = ?, non-zero causes gpf! strings are ok...(?) 'szTitle = Dialog title, specify vbNullString for 'default ("Run") 'szPrompt = Dialog prompt, specify vbNullString for 'default ("Type the name...") 'If uFlags is the following constant, the string from 'last program run will not appear in the dialog's 'combo box (that's all I found...) Public Const shrdNoMRUString = &H2 '2nd bit is set 'If there is some way to set & rtn the command 'line, I didn't find it... 'Always returns 0 (?) |
|||||||||||||||||||||||||||||||||||
Form Code | |||||||||||||||||||||||||||||||||||
Once the form has been designed and saved as shown in the illustration, add the following code to the form: | |||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||
Option Explicit Private Sub cmdEnd_Click() Unload Me End Sub Private Sub Form_Load() 'We'll need this flag to determine if 'strings should be converted to Unicode bIsWinNT = IsWinNT() Me.Move (Screen.Width - Me.Width) / 2, (Screen.Height - Me.Height) / 2 'Setup the controls txtRunTitle = "Run This Puppy" txtRunPrompt = "Enter the name of a program to run, _ or select a file using the Browse button:" If bIsWinNT Then txtRestartPrompt = "its your call..." & vbCrLf & vbCrLf With cboRestartOp .AddItem "0 - EWX_LOGOFF" .AddItem "1 - EWX_SHUTDOWN" 'NT needs SE_SHUTDOWN_NAME prive" .AddItem "2 - EWX_REBOOT" 'NT needs SE_SHUTDOWN_NAME priv" .AddItem "4 - EWX_FORCE" .AddItem "8 - EWX_POWEROFF" 'NT needs SE_SHUTDOWN_NAME priv" .Text = "" End With Else 'Win95/98 txtRestartPrompt = "Warning...!" & vbCrLf & _ " Clicking Yes will end the windows session and close" & vbCrLf & _ " all programs without any prompt to save changes...!" & vbCrLf & vbCrLf With cboRestartOp .AddItem "1 - exit (shutdown), no def prompt" .AddItem "2 - restart computer" .Text = "" End With End If End Sub Private Sub cmdRestartDlg_Click() '---------------------------------------------------- 'Restart system message box: 'A Yes click will end the Windows session **immediately**! '---------------------------------------------------- Dim sPrompt As String Dim uFlag As Long If chkRestartDefaults = 0 Then sPrompt = CheckString(txtRestartPrompt) End If Select Case cboRestartOp.ListIndex Case -1: uFlag = Val(cboRestartOp.Text) Case 0: uFlag = shrsExitNoDefPrompt Case 1: uFlag = shrsRebootSystem End Select If SHRestartSystemMB(hWnd, sPrompt, uFlag) = vbYes Then MsgBox "bye-bye..." 'Never gets here...! End If End Sub Private Sub cmdRunDlg_Click() '---------------------------------------------------- 'Windows 'Run' dialog '---------------------------------------------------- Dim sTitle As String Dim sPrompt As String If chkRunDefaults Then 'sets bit 2 if checked Call SHRunDialog(hWnd, 0, 0, vbNullString, vbNullString, -chkRunNoMRU) Else sTitle = CheckString(txtRunTitle) sPrompt = CheckString(txtRunPrompt) Call SHRunDialog(hWnd, 0, 0, sTitle, sPrompt, -chkRunNoMRU) End If End Sub Private Sub cmdShutDown_Click() '---------------------------------------------------- 'Shut Down Windows dialog '---------------------------------------------------- Call SHShutDownDialog(0) End Sub |
|||||||||||||||||||||||||||||||||||
Comments | |||||||||||||||||||||||||||||||||||
Save the project before running, lest you hit Yes at the wrong moment. | |||||||||||||||||||||||||||||||||||
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |