• Welcome to Jose's Read Only Forum 2023.
 

Windows Shell Functions Examples

Started by José Roca, August 29, 2011, 02:27:46 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

José Roca

 
The Windows UI provides users with access to a wide variety of objects necessary for running applications and managing the operating system. The most numerous and familiar of these objects are the folders and files that reside on computer disk drives. There are also a number of virtual objects that allow the user to perform tasks such as sending files to remote printers or accessing the Recycle Bin. The Shell organizes these objects into a hierarchical namespace and provides users and applications with a consistent and efficient way to access and manage objects.

José Roca

 
The following code example uses SHGetFileInfo to retrieve the display name of the Recycle Bin, identified by its PIDL.


#COMPILE EXE
#DIM ALL
#INCLUDE ONCE "shlobj.inc"

FUNCTION PBMAIN () AS LONG

   LOCAL hr AS LONG
   LOCAL pidl AS ITEMIDLIST PTR
   LOCAL sfi AS SHFILEINFO
   
   hr = SHGetFolderLocation(%NULL, %CSIDL_BITBUCKET, %NULL, 0, pidl)
   IF SUCCEEDED(hr) THEN
      hr = SHGetFileInfo(BYVAL pidl, -1, sfi, SIZEOF(sfi), %SHGFI_PIDL OR %SHGFI_DISPLAYNAME)
      IF SUCCEEDED(hr) THEN MSGBOX sfi.szDisplayName
      CoTaskMemFree pidl
   END IF

END FUNCTION


José Roca

 
The following example illustrates the use of the ShellAbout function.


#COMPILE EXE
#DIM ALL
#INCLUDE "windows.inc"

FUNCTION PBMAIN () AS LONG

   ShellAbout %NULL, "About MyApplication#Application Name", _
      "Copyright © 2007" + $CRLF & "Your Name, etc...", %NULL

END FUNCTION


José Roca

 
The following code retrieves the name of and handle to the executable (.exe) file associated with the specified file name.


#COMPILE EXE
#DIM ALL
#INCLUDE "windows.inc"

FUNCTION PBMAIN () AS LONG

   LOCAL hInstance AS DWORD
   LOCAL szFileName AS ASCIIZ * %MAX_PATH
   LOCAL szDirectory AS ASCIIZ * %MAX_PATH
   LOCAL szResult  AS ASCIIZ * %MAX_PATH

   szFileName = "Test.txt"
   hInstance = FindExecutable(szFileName, szDirectory, szResult)
   ? szResult
   #IF %DEF(%PB_CC32)
      WAITKEY$
   #ENDIF

END FUNCTION


José Roca

 
We can force SHBrowseForFolder to start at a specific directory by using the callback function facility:


#COMPILE EXE
#DIM ALL
#INCLUDE ONCE "windows.inc"
#INCLUDE ONCE "shlobj.inc"

FUNCTION BrowseForFolder (BYVAL hwnd AS DWORD, BYVAL strStartFolder AS STRING) AS STRING

   LOCAL szBuffer   AS ASCIIZ * %MAX_PATH
   LOCAL bi         AS BROWSEINFO
   LOCAL lpIDList   AS LONG

   bi.hwndOwner    = hwnd
   bi.ulFlags      = %BIF_RETURNONLYFSDIRS OR %BIF_USENEWUI
   bi.lpfnCallback = CODEPTR(BrowseForFolderProc)
   bi.lParam       = STRPTR(strStartFolder)
   lpIDList        = SHBrowseForFolder(bi)

   IF ISTRUE lpIDList AND SHGetPathFromIDList(BYVAL lpIDList, szBuffer) THEN
      FUNCTION = szBuffer
      CoTaskMemFree lpIDList
   END IF

END FUNCTION

FUNCTION BrowseForFolderProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   IF wMsg = %BFFM_INITIALIZED THEN
      SendMessage hwnd, %BFFM_SETSELECTION, %TRUE, lParam
   END IF
   FUNCTION = %S_OK

END FUNCTION

FUNCTION PBMAIN () AS LONG

   LOCAL strFolder AS STRING
   strFolder = BrowseForFolder(0, "C:\PBWIN10")
   ? strFolder

END FUNCTION


José Roca

 
The following example uses the AssocQueryStringW function to retrieve the executable associated with the .txt extension.


' ########################################################################################
' The following example illustrates the use of the AssocQueryStringW function.
' ########################################################################################

#COMPILE EXE
#DIM ALL
#INCLUDE ONCE "shlwapi.inc"

' ========================================================================================
' Main
' ========================================================================================
FUNCTION PBMAIN () AS LONG

   LOCAL hr AS LONG
   LOCAL cchOut AS DWORD
   LOCAL wszAssoc AS WSTRINGZ * 260
   LOCAL bstrOut AS WSTRING

   wszAssoc = ".txt"
   hr = AssocQueryStringW(%ASSOCF_NOTRUNCATE OR %ASSOCF_REMAPRUNDLL OR %ASSOCF_INIT_IGNOREUNKNOWN, _
      %ASSOCSTR_EXECUTABLE, wszAssoc, BYVAL %NULL, BYVAL %NULL, cchOut)
   IF hr = %S_FALSE THEN
      bstrOut = SPACE$(cchOut)
      hr = AssocQueryStringW(%ASSOCF_NOTRUNCATE OR %ASSOCF_REMAPRUNDLL OR %ASSOCF_INIT_IGNOREUNKNOWN, _
         %ASSOCSTR_EXECUTABLE, wszAssoc, BYVAL %NULL, BYVAL STRPTR(bstrOut), cchOut)
      IF hr = %S_OK THEN
         ? bstrOut
      ELSE
         ? "Error &H" & HEX$(hr)
      END IF
   ELSE
      ? "Error &H" & HEX$(hr)
   END IF

   #IF %DEF(%PB_CC32)
      WAITKEY$
   #ENDIF

END FUNCTION
' ========================================================================================


José Roca

 
The following example uses the RegEnumEx API function to parse the registry, selects the names that begin with a dot and calls the SHGetFileInfo API function to retrieve its type.


#COMPILE EXE
#DIM ALL
#INCLUDE "windows.inc"

FUNCTION PBMAIN () AS LONG

   LOCAL dwIndex AS DWORD
   LOCAL szName AS ASCIIZ * %MAX_PATH
   LOCAL szClass AS ASCIIZ * %MAX_PATH
   LOCAL sfi AS SHFILEINFO
   
   DO
      IF RegEnumKeyEx (%HKEY_CLASSES_ROOT, _
                       dwIndex, _
                       szName, _
                       SIZEOF(szName), _
                       0, _
                       szClass, _
                       SIZEOF(szClass), _
                       BYVAL %NULL) <> %ERROR_SUCCESS THEN EXIT DO
      IF LEFT$(szName, 1) = "." THEN
         ' Get the file type
         IF SHGetFileInfo (szName, 0, _
                          sfi, LEN(sfi), _
                          %SHGFI_TYPENAME OR %SHGFI_USEFILEATTRIBUTES) THEN
            PRINT "Name: " & szName & " Type: " & sfi.szTypeName
         END IF
      END IF
      dwIndex = dwIndex + 1
   LOOP
   
   WAITKEY$

END FUNCTION


José Roca

 
Opens an instance of Explorer with the Printers and Faxes folder selected.


#COMPILE EXE
#DIM ALL
#INCLUDE "windows.inc"

FUNCTION PBMAIN () AS LONG

   ShellExecute 0, "Open", _
                "explorer.exe", _
                "/e,::{2227A280-3AEA-1069-A2DE-08002B30309D}", _
                BYVAL %NULL, %SW_SHOW

END FUNCTION


José Roca

 
The Pick Icon Common Dialog displays a dialog box that allows a user to select an icon from a module.

Shell32.dll exports a function that allows to display the Pick Icon Common Dialog. This function is exported by name in Windows XP, but only by ordinal in previous versions. Besides, the icon path parameter must be an asciiz string in Windows 95/98 and unicode in 2000/XP.


' ========================================================================================
' PICKICONDIALOG.BAS
' Demonstrates the use of the PickIconDlg function.
' 1. Clik the "Pick" button to activate the PickIconDlg Common Dialog.
' 2. Choose an icon, and click OK.
' The icon of the application will be changed with the selected one.
' Note: The first time that you activate the PickIconDlg, the dialog will show the icons
' stored in the resource file of the application. Click the Browse button to select
' another file (.exe, .dll) containing a resource file with icons or an icon file.
' ========================================================================================

#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE "windows.inc"
#INCLUDE "shlobj.inc"
#RESOURCE RES, "PickIconDialog.res"

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WINMAIN (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS ASCIIZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   LOCAL hWndMain AS DWORD
   LOCAL hCtl AS DWORD
   LOCAL hFont AS DWORD
   LOCAL wcex AS WndClassEx
   LOCAL rc AS RECT
#IF %DEF(%UNICODE)
   LOCAL szClassName AS WSTRINGZ * 80
   LOCAL szCaption AS WSTRINGZ * 255
#ELSE
   LOCAL szClassName AS ASCIIZ * 80
   LOCAL szCaption AS ASCIIZ * 255
#ENDIF

   hFont = GetStockObject(%ANSI_VAR_FONT)

   ' Register the window class
   szClassName        = "PickIconDialog"
   wcex.cbSize        = SIZEOF(wcex)
   wcex.style         = %CS_HREDRAW OR %CS_VREDRAW
   wcex.lpfnWndProc   = CODEPTR(WndProc)
   wcex.cbClsExtra    = 0
   wcex.cbWndExtra    = 0
   wcex.hInstance     = hInstance
   wcex.hCursor       = LoadCursor (%NULL, BYVAL %IDC_ARROW)
   wcex.hbrBackground = GetStockObject(%WHITE_BRUSH)
   wcex.lpszMenuName  = %NULL
   wcex.lpszClassName = VARPTR(szClassName)
   wcex.hIcon         = LoadIcon (hInstance, "OBJECTS")
   wcex.hIconSm       = LoadIcon (hInstance, "OBJECTS")
   RegisterClassEx wcex

   ' Window caption
   szCaption = "Pick Icon Dialog Demo"

   ' Create a window using the registered class
   hWndMain = CreateWindowEx(%WS_EX_CONTROLPARENT, _           ' extended style
                             szClassName, _                    ' window class name
                             szCaption, _                      ' window caption
                             %WS_OVERLAPPEDWINDOW OR _
                             %WS_CLIPCHILDREN, _               ' window style
                             %CW_USEDEFAULT, _                 ' initial x position
                             %CW_USEDEFAULT, _                 ' initial y position
                             %CW_USEDEFAULT, _                 ' initial x size
                             %CW_USEDEFAULT, _                 ' initial y size
                             %NULL, _                          ' parent window handle
                             0, _                              ' window menu handle
                             hInstance, _                      ' program instance handle
                             BYVAL %NULL)                      ' creation parameters

   hCtl = CreateWindowEx(0, "BUTTON", "&Pick", %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_FLAT, _
          0, 0, 0, 0, hWndMain, %IDOK, hInstance, BYVAL %NULL)
   IF hFont THEN SendMessage hCtl, %WM_SETFONT, hFont, 0

   hCtl = CreateWindowEx(0, "BUTTON", "&Close", %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_FLAT, _
          0, 0, 0, 0, hWndMain, %IDCANCEL, hInstance, BYVAL %NULL)
   IF hFont THEN SendMessage hCtl, %WM_SETFONT, hFont, 0

   ' Show the window
   ShowWindow hWndMain, nCmdShow
   UpdateWindow hWndMain

   ' Message handler loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      IF ISFALSE IsDialogMessage(hWndMain, uMsg) THEN
         TranslateMessage uMsg
         DispatchMessage uMsg
      END IF
   WEND

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure
' ========================================================================================
FUNCTION WndProc (BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   LOCAL  hr AS LONG
   LOCAL  rc AS RECT
   STATIC wszIconPath AS WSTRINGZ * %MAX_PATH
   STATIC iIconIndex AS LONG
   STATIC hIcon AS DWORD

   SELECT CASE wMsg

      CASE %WM_CREATE
         iIconIndex = 5    ' Initial icon index
         EXIT FUNCTION

      CASE %WM_SIZE
         ' Resize the two sample buttons of the dialog
         IF wParam <> %SIZE_MINIMIZED THEN
            GetClientRect hWnd, rc
            MoveWindow GetDlgItem(hWnd, %IDOK), (rc.nRight - rc.nLeft) - 185, (rc.nBottom - rc.nTop) - 35, 75, 23, %TRUE
            MoveWindow GetDlgItem(hWnd, %IDCANCEL), (rc.nRight - rc.nLeft) - 95, (rc.nBottom - rc.nTop) - 35, 75, 23, %TRUE
            EXIT FUNCTION
         END IF

      CASE %WM_COMMAND

         SELECT CASE LOWRD(wParam)

            CASE %IDOK
               IF HIWRD(wParam) = %BN_CLICKED THEN
                  IF LEN(wszIconPath) = 0 THEN
                     ' Get the full path of our executable
                     GetModuleFileName %NULL, wszIconPath, %MAX_PATH
                  END IF
                  ' Activate the Pick Icon Common Dialog Box
                  hr = PickIconDlg(0, wszIconPath, SIZEOF(wszIconPath), iIconIndex)
                  ' If an icon has been selected...
                  IF hr = 1 THEN
                     ' Destroy previously loaded icon, if any
                     IF hIcon THEN DestroyIcon hIcon
                     ' Get the handle of the new selected icon
                     hIcon = ExtractIcon(GetModuleHandle(""), wszIconPath, iIconIndex)
                     ' Replace the application icons
                     IF hIcon THEN
                        SendMessage (hwnd, %WM_SETICON, %ICON_SMALL, hIcon)
                        SendMessage (hwnd, %WM_SETICON, %ICON_BIG, hIcon)
                     END IF
                  END IF
                  EXIT FUNCTION
               END IF

            CASE %IDCANCEL
               ' Close the application
               IF HIWRD(wParam) = %BN_CLICKED THEN
                  SendMessage hWnd, %WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF

         END SELECT

      CASE %WM_DESTROY
         ' Destroy the icon and terminate the application
         IF hIcon THEN DestroyIcon hIcon
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
The Run File Common Dialog displays a dialog box that allows a user to run an application. It is the dialog that you see when launching applications from the Start/Run menu.

Shell32.dll exports a function that allows to display the Run File Common Dialog. This function is exported by ordinal 61. Besides, the string parameters must be Ansi in Windows 95/98 and Unicode in NT Platforms.

A nice feature of this dialog is that it allows you to control which applications the user may run. When the user selects the OK button, your parent window is sent a notification with details of the program that is about to be started. The notification is in the form of a WM_NOTIFY message with the notification code set to RFN_VALIDATE (-510) and the lParam pointing to an NM_RUNFILEDLG structure. The lpFile and lpDirectory members have been declared as DWORD to allow to use it with all Windows versions (they are pointers to Ansi strings in Windows 95/98 and Unicode in Windows NT platforms).

AfxRunFileDialog wrapper procedure (located in AfxDlg.inc):


' ========================================================================================
' Helper procedure to activate the run file dialog.
' * hwndOwner identifies the window that owns the dialog box.
' * hIcon is the handle of the icon that will be displayed in the dialog. If it is NULL,
'   the default icon will be used.
' * lpstrDirectory points to a string that specifies the working directory.
' * lpstrTitle points to a string to be placed in the title bar of the dialog box. If it
'   is NULL, the default title is used.
' * lpstrDescription points to a string that is displayed in the dialog, briefly informing
'   the user what to do. If it is NULL, the default description is used.
' * uFlags is a set of bit flags that specify other properties of the dialog.
'     - RFF_NOBROWSE       &H01    Removes the browse button.
'     - RFF_NODEFAULT      &H02    No default item selected.
'     - RFF_CALCDIRECTORY  &H04    Calculates the working directory from the file name.
'     - RFF_NOLABEL        &H08    Removes the edit box label.
'     - RFF_NOSEPARATEMEM  &H20    Removes the Separate Memory Space check box (Windows NT only).
' A nice feature of this dialog is that it allows you to control which applications the
' user may run. When the user selects the OK button, your parent window is sent a
' notification with details of the program that is about to be started. The notification is
' in the form of a WM_NOTIFY message with the notification code set to RFN_VALIDATE (-510)
' and the lParam pointing to an NM_RUNFILEDLG structure.
' Note: The three string parameters, lpstrDirectory, lpstrTitle and lpstrDescription must
' be ansi in Win95/98 and unicode in NT Platforms.
' ========================================================================================
SUB AfxRunFileDialog ( _
   BYVAL hwndOwner AS DWORD _                    ' HWND hwndOwner
, BYVAL hIcon AS DWORD _                        ' HICON hIcon
, BYREF lpstrDirectory AS WSTRINGZ _            ' LPWSTR lpstrDirectory
, BYREF lpstrTitle AS WSTRINGZ _                ' LPWSTR lpstrTitle
, BYREF lpstrDescription AS WSTRINGZ _          ' LPWSTR lpstrDescription
, BYVAL uFlags AS DWORD _                       ' UINT uFlags
   )                                             ' void

   LOCAL hr AS LONG
   LOCAL hLib AS DWORD
   LOCAL pRunDlg AS DWORD

   ' // Load the shell library
   hLib = LoadLibrary("SHELL32.DLL")
   IF hLib = %NULL THEN EXIT SUB

   ' // Get the address of the RunFileDlg (ordinal 61)
   pRunDlg = GetProcAddress(hLib, BYVAL MAK(LONG, 61, 0))
   IF ISTRUE pRunDlg THEN
      ' // Call the Run File dialog
      CALL DWORD pRunDlg USING AfxRunFileDialog(hwndOwner, hIcon, lpstrDirectory, lpstrTitle, lpstrDescription, uFlags)
   END IF

   ' // Free the library
   FreeLibrary hLib

END SUB
' ========================================================================================


The following example demonstrates the use of AfxRunFileDialog.


#COMPILE EXE
#DIM ALL
%UNICODE = 1

' // Include files for external files
#INCLUDE ONCE "CWindow.inc"    ' // CWindow class
#INCLUDE ONCE "comdlg32.inc"   ' // Common dialogs

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
'   SetProcessDPIAware

   ' // Create an instance of the class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   pWindow.CreateWindow(%NULL, "CWindow with Run File Dialog", 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Set the client size
   pWindow.SetClientSize 500, 320
   ' // Center the window
   pWindow.CenterWindow

   ' // Add buttons
   pWindow.AddButton(pWindow.hwnd, %IDOK, "&Start", 0, 0, 75, 23)
   pWindow.AddButton(pWindow.hwnd, %IDCANCEL, "&Close", 0, 0, 75, 23)


   ' // Default message pump (you can replace it with your own)
   pWindow.DoEvents(nCmdShow)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main callback function.
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   STATIC hInstance AS DWORD        ' // Instance handle
   STATIC lpc AS CREATESTRUCT PTR   ' // Pointer to the creation parameters
   STATIC pWindow AS IWindow        ' // Reference to the IWindow interface

   SELECT CASE uMsg

      CASE %WM_CREATE
         ' // Pointer to the creation parameters
         lpc = lParam
         ' // Instance handle
         hInstance = @lpc.hInstance
         ' // Get a reference to the IWindow interface from the CREATESTRUCT structure
         pWindow = CWindow_GetObjectFromCreateStruct(lParam)
         EXIT FUNCTION

      CASE %WM_COMMAND
         SELECT CASE LO(WORD, wParam)

            CASE %IDOK
               AfxRunFileDialog hwnd, 0, "", "Run File Dialog", "", 0' %RFF_NOSEPARATEMEM
               EXIT FUNCTION

            CASE %IDCANCEL
               ' // If the Escape key has been pressed...
               IF HI(WORD, wParam) = %BN_CLICKED THEN
                  ' // ... close the application by sending a WM_CLOSE message
                  SendMessage hwnd, %WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF

         END SELECT

      ' // Process the RFN_VALIDATE notification message
      CASE %WM_NOTIFY
         LOCAL hr AS LONG
         LOCAL ptnmhdr AS NMHDR PTR
         LOCAL ptnmrfd AS NM_RUNFILEDLG PTR
         ptnmhdr = lParam
         SELECT CASE @ptnmhdr.code
            CASE %RFN_VALIDATE
               ptnmrfd = lParam
               LOCAL wszPath AS WSTRINGZ * %MAX_PATH
               wszPath = @ptnmrfd.@lpDirectory & @ptnmrfd.@lpFile
               hr = MessageBox(BYVAL hwnd, "Run the file " & wszPath, "", _
                               %MB_YESNOCANCEL OR %MB_ICONQUESTION OR %MB_APPLMODAL)
               SELECT CASE hr
                  CASE %IDYES : FUNCTION = %RF_OK
                  CASE %IDNO  : FUNCTION = %RF_RETRY
                  CASE ELSE   : FUNCTION = %RF_CANCEL
               END SELECT
               EXIT FUNCTION
         END SELECT

      CASE %WM_SIZE
         ' // If the window isn't minimized, resize it
         IF wParam <> %SIZE_MINIMIZED THEN
            ' // Resize the sample button
            pWindow.MoveWindow GetDlgItem(hwnd, %IDOK), pWindow.ClientWidth - 195, pWindow.ClientHeight - 35, 75, 23, %TRUE
            pWindow.MoveWindow GetDlgItem(hwnd, %IDCANCEL), pWindow.ClientWidth - 95, pWindow.ClientHeight - 35, 75, 23, %TRUE
         END IF

      CASE %WM_DESTROY
         ' // End the application
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================