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.
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
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
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
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
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
' ========================================================================================
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
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
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
' ========================================================================================
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
' ========================================================================================