B. The Windows Shell

Page 449
  B. The Windows Shell  
   
  In this chapter, we will give a brief overview of the Window shell. Our purpose is to acquaint you with the general features of the shell. These features are not terribly difficult to implement, and if you have made it this far through the book, you should have no real trouble extracting any further information about the shell that is not covered in this chapter directly from the documentation.  
   
  A shell is a Windows application that provides control over other applications. The functions of the Windows shell are primarily contained in the shell32.dll library. Installation of a particular version of Internet Explorer also alters (or enhances?) the current Windows shell.  
   
  The shell library shell32.dll supports a variety of features, such as:  
   
  The dragging-and-dropping of files from the File Manager  
   
  File associations  
   
  Extraction of icons from executable files  
   
  The System Tray  
   
  File operations, such as sending a file to the recycle bin  
   
  Miscellaneous shell functions (such as adding a document to the most recently used documents list)  
   
  We emphasize that the implementation of various shell features depends on the version of shell32.dll and comctl32.dll that is currently installed on the system, and this depends on the version of Windows and Internet Explorer that is installed. According to the documentation, version numbers are as follows:  
   
  Version 4.00: Windows 95/4.0  
   
  Version 4.70: Internet Explorer 3.x  
Page 450
   
  Version 4.71: Internet Explorer 4.0  
   
  Version 4.72: Internet Explorer 4.01  
   
  Version 5.00: Windows NT 5.0 and Internet Explorer 5.0  
   
  The documentation does not make it clear as to what precisely the version number applies. It does say that the versions of shell32.dll and comctl32.dll should be the same (except for Version 5.00), but this may or may not be the case on a given system. For instance, the rpiPEInfo utility discussed earlier in this book reports the following for my system:  
 
  Shell32.dll: File Version 4.0.1381.4
Comctrl32.dll: File Version 4.72.3110.1
 
   
  (My system has Internet Explorer 4.0 Version 4.72.3110.8 installed.) Since I did not deliberately install a new version of either of these files directly, something seems amiss. At the very least, this whole issue makes it difficult to write shell-related applications that will run on the majority of extant systems.  
   
  Now let us discuss some of the features of the Windows shell.  
 
  Drag-and-Drop  
   
  The Windows shell makes it relatively simple to enable a VB control to recognize files that are dragged from Windows Explorer and dropped on that control. The main catch is that Windows notifies the control that a file (or files) has been dragged and dropped by sending that control a message. Thus, we need to sub-class the control!  
   
  The code in the rpiShell example demonstrates how to enable drag-and-drop features under VB. Figure B-1 shows the main window (this project also demonstrates file associations and registry manipulation, discussed in Appendix C, The Registry and Private Profiles).  
   
  To demonstrate drag-and-drop, just hit the enable button and drag a single file from an Explorer window to the picture box on the right of the buttons. The fully qualified name of the file will appear in the text box.  
   
  The code for this feature is quite simple. Aside from subclassing the picture box (we discussed subclassing in Chapter 18, Windows Subclassing), we need to call the DragAcceptFiles API shell function, whose VB declaration is:  
 
  Declare Sub DragAcceptFiles Lib "shell32.dll" _
(ByVal hWnd As Long, ByVal fAccept As Long)
 
   
  Here hWnd is the handle of the window to which messages are sent by the shell, and fAccept should be set to True to enable drag-and-drop and False to disable it.  
Page 451
   
  0451-01.gif  
   
  Figure B-1.
Illustrating drag-and-drop
 
   
  The following code takes care of subclassing and enabling drag-and-drop (bIsSubClassed is a module-level variable):  
 
  Sub EnableDrag()

' Subclass the picture box
hPrevWndProc = SetWindowLong(Picture1.hWnd, GWL_WNDPROC, AddressOf WindowProc)

If hPrevWndProc <> 0 Then

   bIsSubclassed = True
   fraDragDrop.Caption = "DragDrop-Enabled"

   ' Set drag and drop
   DragAcceptFiles Picture1.hWnd, True

End If

End Sub
 
   
  The following code turns off both drag-and-drop and subclassing:  
 
  Sub DisableDrag()

Dim lret As Long
 
 

Page 452
 
  ' Remove Subclass if appropriate
If bIsSubclassed Then

   lret = SetWindowLong(Picture1.hWnd, GWL_WNDPROC, hPrevWndProc)

   bIsSubclassed = False
   fraDragDrop.Caption = "DragDrop-Disabled"

   ' Clear drag and drop
   DragAcceptFiles Picture1.hWnd, False

End If

End Sub
 
   
  As mentioned, when a file is dragged and dropped over the picture box, the Windows shell will send a WM_DROPFILES message to the picture box. The following window procedure processes this message.  
 
  Public Function WindowProc(ByVal hWnd As Long, ByVal iMsg As Long, _
   ByVal wParam As Long, ByVal lParam As Long) As Long

Dim lpbuffer As String
lpbuffer = String$(1024, 0)

Select Case iMsg

   Case WM_DROPFILES
      ' Grab the file's name
      DragQueryFile wParam, 0, lpbuffer, 1024
      ' Print it
      frmShell.txtDragDrop.Text = lpbuffer
      ' Release resources
      DragFinish wParam

End Select

' Call original window procedure
WindowProc = CallWindowProc(hPrevWndProc, hWnd, iMsg, wParam, lParam)

End Function
 
   
  In response to a WM_DROPFILES message, we need to call one or both of the shell functions DragQueryFile or DragQueryPoint. The former returns the name (and path) for the dragged file, and the latter returns the location that the file was dropped within the picture box. Also, we must release used resources by calling DragFinish. Here are the declarations:  
 
  Declare Function DragQueryFile Lib "shell32.dll" Alias "DragQueryFileA" (_
   ByVal HDROP As Long, ByVal UINT As Long, _
   ByVal lpStr As String, ByVal ch As Long) As Long
 
 

Page 453
 
  Declare Function DragQueryPoint Lib "shell32.dll" (_
   ByVal HDROP As Long, lpPoint As POINTAPI) As Long

Declare Sub DragFinish Lib "shell32.dll" (ByVal HDROP As Long)
 
   
  The hDROP parameter that appears in each function is passed to us in the wParam parameter of the window procedure. It identifies the dropped file or files. (Our example deals with just a single dropped file, but you can easily enhance it to deal with multiple files dropped at one time.)  
 
  File Associations  
   
  As a Windows user, you are no doubt familiar with the fact that Windows can associate a file extension with an application (executable file). In this way, double-clicking on a file in an Explorer window, or choosing Open from the context-sensitive pop-up menu (raised by a click of the right mouse button) will cause Windows to execute the associated application and feed it the file in question.  
   
  The Windows shell permits us to take advantage of Windows file associations in VB applications. In particular, we can use the FindExecutable shell function to retrieve the complete path and filename of the application (executable) that is associated with a given file. Then we can use ShellExecute to open the file, using that application.  
   
  The VB declaration for FindExecutable is:  
 
  Declare Function FindExecutable Lib "shell32.dll" Alias "FindExecutableA" _
   ByVal lpFile As String, ByVal lpDirectory As String, _
   ByVal lpResult As String) As Long
 
   
  Here lpFile is the name of the file in question, lpDirectory is the name of a directory that is made the default directory. This optional value (it can be NULL) is used to find the file specified by lpFile when lpFile does not contain a complete path. Finally, lpResult parameter is a string buffer that will receive the fully qualified name of the application's executable. It must have length at least MAX_PATH ( = 260).  
   
  The rpiShell application shown in Figure B-1 also illustrates the use of FindExecutable. The code behind the Associate button is simply:  
 
  Private Sub cmdAssociate_Click()

Dim sFile As String
Dim sEXE As String
sEXE = String$(MAX_PATH, 0)

sFile = txtFile
If sFile = "" Then Exit Sub
 
 

Page 454
 
  FindExecutable sFile, vbNullString, sEXE

txtEXE = sEXE
End Sub
 
   
  The ShellExecute function can either open a file or print it. The VB declaration is:  
 
  Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (_
   ByVal hwnd As Long, _
   ByVal lpOperation As String, _
   ByVal lpFile As String, _
   ByVal lpParameters As String, _
   ByVal lpDirectory As String, _
   ByVal nShowCmd As Long _
) As Long
 
   
  As an example, referring to Figure B-1, the code behind the Execute button is:  
 
  Private Sub cmdExecute_Click()

Dim sFile As String
Dim lResp As Long

sFile = txtFile

lResp = ShellExecute (Me.hwnd, "open", sFile, vbNullString, _
   vbNullString, SW_SHOWNORMAL)

End Sub
 
   
  Note that the documentation indicates that the final parameter should be set to 0 for a document file, but this does not seem to work on my system!  
   
  The ShellExecute function can also be used to open a folder in Windows Explorer, using one of the following syntaxes, which differ only in the second parameter:  
 
  ShellExecute(handle, vbNullString, <PathToFolder>, _
   vbNullString, vbNullString, SW_SHOWNORMAL);

ShellExecute(handle, "open", <PathToFolder>,_
   vbNullString, vbNullString, SW_SHOWNORMAL);

ShellExecute(handle, "explore", <PathToFolder>, _
   vbNullString, vbNullString, SW_SHOWNORMAL);
 
   
  The first two versions of ShellExecute will open the specified folder. For instance, the code:  
 
  ShellExecute Me.hWnd, "open", "d:\temp", _
   vbNullString, vbNullString, SW_SHOWNORMAL
 
   
  displays the dialog shown in Figure B-2.  
   
  The third call to ShellExecute opens a new Windows Explorer window and displays the contents of the specified folder.  
Page 455
   
  0455-01.gif  
   
  Figure B-2.
Illustrating ShellExecute
 
 
  The System Tray  
   
  The Windows shell also implements functions for dealing with the Windows System Tray, located on the taskbar.  
   
  It seems safe to assume that you are familiar at some level or other with the Windows System Tray. The Windows shell makes it easy to place icons in the System Tray and use them to execute code in response to mouse activity. For this, we use the Shell_NotifyIcon function:  
 
  Public Declare Function Shell_NotifyIcon Lib "shell32"_
Alias "Shell_NotifyIconA" (_
   ByVal dwMessage As Long, _
   ByRef pnid As utNOTIFYICONDATA _
) As Boolean
 
   
  This function can be used to add, modify or delete an icon from the System Tray. Accordingly, the dwMessage parameter can be one of the following:  
   
  NIM_ADD  
   
  NIM_MODIFY  
   
  NIM_DELETE  
   
  The pnid parameter is the address of a NOTIFYICONDATA structure, the content of which depends on the value of dwMessage:  
 
  Public Type NOTIFYICONDATA
   cbSize As Long
   hwnd As Long
   uID As Long
   uFlags As Long
   uCallbackMessage As Long
   hIcon As Long
   szTip(1 To 64) As Byte
End Type
 
Page 456
   
  The members of this structure are:  
 
  cbSize
Size of this structure, in bytes, which is 88 (It is more professional to use the LenB function.)
 
 
  hWnd
Handle of the window that will receive notification messages associated with the System Tray icon.
 
 
  uID
An application-defined identifier of the System Tray icon. Can be 0.
 
 
  uFlags
A combination of flags indicating which of the other members of the structure contain valid data. The possibilities are:
 
 
  NIF_ICON
The hIcon member is valid.
 
 
  NIF_MESSAGE
The uCallbackMessage member is valid.
 
 
  NIF_TIP
The szTip member is valid.
 
 
  uCallbackMessage
This is a message ID. Windows will send this message to the window identified  by the hwnd member when a mouse event occurs within the bounding rectangle of the System Tray icon.
 
 
  hIcon
Handle to the icon to add, modify, or delete.
 
 
  szTip
The tooltip text to display for the icon.
 
   
  According to the documentation, we should set the callback function to an otherwise unused mouse event. The example in the documentation is the MouseMove event of the form, which seems reasonable. This is done by setting:  
 
  nid.hwnd = Me.hWnd
nid.uCallbackMessage = WM_MOUSEMOVE
 
   
  In this case when a mouse event occurs for the System Tray icon, Windows will fire the MouseMove event of the form. Moreover, it sends the mouse message ID in the X parameter of the form's MouseMove event, as follows:  
 
  X = MessageID*Screen.TwipsPerPixelX  
   
  so to recover the message ID, we must divide by Screen.TwipsPerPixelX. (See the upcoming example.)  
Page 457
   
  An Example  
   
  To illustrate, the following code will add or delete an icon from the System Tray and respond to left-button double-clicks or right-button up events. The Load event sets up the NOTIFYICONDATA structure:  
 
  Private Sub Form_Load()

Dim sTip As String

' Fill in NOTIFYICONDATA structure
sTip = "Test tip"
CopyMemory nid.szTip(1), ByVal sTip, LenB(sTip)

nid.cbSize = LenB(nid)
nid.hwnd = Me.hwnd
nid.uID = 0
nid.hIcon = Me.Icon.Handle
nid.uFlags = NIF_ICON Or NIF_MESSAGE Or NIF_TIP

' Set callback message to mouse move
nid.uCallbackMessage = WM_MOUSEMOVE

End Sub
 
   
  Just for the sake of illustration, the form's MouseMove event responds to System Tray icon mouse events by sending a line to the Immediate window.  
 
  Private Sub Form_MouseMove (Button As Integer, Shift As Integer, X As Single, Y As
Single)

' When mouse is passed over tray icon,
' X value is MessageID * Screen.TwipsPerPixelX

Select Case X / Screen.TwipsPerPixelX

Case WM_LBUTTONBLCLK
   Debug.Print "Double Click"
Case WM_RBUTTONUP
   Debug.Print "Right"
End Select

End Sub
 
   
  Finally, the following code adds or removes the icon from the System Tray.  
 
  Private Sub cmdAdd_Click()
   Shell_NotifyIcon NIM_ADD, nid
End Sub

Private Sub cmdDelete_Click()
   Shell_NotifyIcon NIM_DELETE, nid
End Sub
 
Page 458
   
  I will leave it to you to come up with some interesting uses for the System Tray and its icons. Let me know if you find a really good one.  
 
  File Operations  
   
  The Windows shell implements a function called SHFileOperation which allows us to copy, rename, or delete a file or folder in a manner that resembles that of Windows Explorer. In particular, copying a file will display the familiar file copying progress dialog (assuming that the copying process takes long enough for Windows to display the dialog), and deleting a file will send it to the Recycle Bin. The function declaration, along with a needed user-defined type declaration, is:  
 
  Type SHFILEOPSTRUCT
   hwnd As Long
   wFunc As Long
   pFrom As String
   pTo As String
   fFlags As Long
   fAnyOperationsAborted As Long
   hNameMappings As Long
   lpszProgressTitle As String
End Type

Declare Function SHFileOperation Lib "Shell32.dll" Alias "SHFileOperationA" ( _
   lpFileOp As SHFILEOPSTRUCT) As Long
 
   
  We will not go into the details of this function, except to give an example of deleting and copying.  
   
  The following code will send a file to the Recycle Bin:  
 
  Dim DelFileOp As SHFILEOPSTRUCT
Dim result As Long

' Initialize the structure
With DelFileOp
   .hwnd = 0
   .wFunc = FO_DELETE
   ' path and name of file to delete
   .pFrom = <filepathname>
   .fFlags = FOF_SILENT Or FOF_ALLOWUNDO Or FOF_NOCONFIRMATION
End With

' Do it
result = SHFileOperation(DelFileOp)

If result <> 0 Then    'Operation failed
   MsgBox "SHFileOperation error"
Else
   If DelFileOp.fAnyOperationsAborted <> 0 Then
      MsgBox "Operation Aborted"
   End If
End If
 
Page 459
   
  The wFunc parameter of the SHFILEOPSTRUCT structure can be set to any one of FO_COPY, FO_DELETE, FO_MOVE, or FO_RENAME. The fFlags parameter can be set to a combination of values that specify particular settings, such as whether or not to require confirmation for the operation in question. The fAnyOperations-Aborted flag is filled in by Windows with True if the user aborted the operation.  
   
  The following code, also in the rpiShell project, will copy a file, displaying the familiar progress dialog that is used by Windows Explorer (provided the copying operation takes long enough for the dialog to appear):  
 
  Private Sub cmdFileCopy_Click()

Dim FileOp As SHFILEOPSTRUCT
Dim result As Long

With FileOp
   .hWnd = 0
   .wFunc = FO_COPY
   .pFrom = InputBox("Enter path and name of file to copy")
   .pTo = InputBox("Enter destination")
   .fFlags = FOF_NOCONFIRMATION
End With

result = SHFileOperation(FileOp)

If result <> 0 Then
   MsgBox Err.LastDllError
Else
   If FileOp.fAnyOperationsAborted <> 0 Then
      MsgBox "Operation Aborted"
   End If
End If

End Sub
 
 
  The Recycle Bin  
   
  The Windows 98 and Windows 2000 shell supports two functions for dealing directly with the Recycle Bin: the SHQueryRecycleBin function returns the number of items and the total size in bytes of a Recycle Bin, and the SHEmptyRecycleBin function empties a Recycle Bin. Note that these functions are not supported under Windows 95 or Windows NT 4.  
   
  The declaration of SHQueryRecycleBin is:  
 
  Declare Function SHQueryRecycleBin Lib "shell32.dll" Alias _
   "SHQueryRecycleBinA" (ByVal sRootPath As String, _
   lpRBInfo As SHQUERYRBINFO) As Long
 
   
  where sRootPath is a string that begins with the drive containing the Recycle Bin (as in ''c:\temp" for the C drive) and SHQUERYRBINFO is declared in C as follows.  
Page 460
 
  struct _SHQUERYRBINFO {
    DWORD cbSize;
    _int64 i64Size;      // the total size of the items in the recycle bin
    _int64 i64NumItems;  // the number of items in the recycle bin
}
 
   
  This is our first encounter with the 64-bit data type _int64. We can translate the structure into VB as:  
 
  Type SHQUERYRBINFO
    cbSize As Long
    lSizeLow As Long
    lSizeHigh As Long
    lCountLow As Long
    lCountHigh As Long
End Type
 
   
  The declaration for SHEmptyRecycleBin is:  
 
  Declare Function SHEmptyRecycleBin Lib "shell32.dll" Alias _
   "SHEmptyRecycleBinA" (ByVal hWnd As Long, ByVal sRootPath As String, _
   ByVal dwFlags As Long) As Long
 
   
  where hWnd is the handle of a window (use Me.hWnd) to receive any dialog messages, sRootPath is the same as in SHQueryRecycleBin, and dwFlags controls the display of confirmation and progress dialogs as follows:  
 
  SHERB_NOCONFIRMATION
No confirmation dialog will be displayed.
 
 
  SHERB_NOPROGRESSUI
No progress dialog will be displayed.
 
 
  SHERB_NOSOUND
No sound will be played when the operation is complete.
 


WIN32 API Programming with Visual Basic
Win32 API Programming with Visual Basic
ISBN: 1565926315
EAN: 2147483647
Year: 1999
Pages: 31
Authors: Steven Roman

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net