Thursday, April 15, 2021

Useful Utilities (at least, I think they are)

Useful Utilities (at least, I think they are)

Like all developers, whatever their preferred language or environment, I have my own personal set of tools and utilities that I use to make life a little easier for myself. Although not particularly generic, or even clever, I find that these little things really help so I offer them here, as is, for your enjoyment, adoption and modification.

The first is a little bit of code that I wrote because I was fed up with mis-spelling column names when writing SQL Statements – especially when working with cursors that included calculated or aliased columns. This little routine, named GetFList() gets the list of field names for a specified alias (or the currently selected alias if nothing is specified) and places them on to the Windows Clipboard. Once there, the list can simply be pasted into whatever window I happen to be working in at the time.  Simple, but it has saved me many hours over the years.
********************************************************************
*** Name.....: GetFList.prg
*** Author...: Andy Kramek
*** Date.....: 7/7/2004
*** Notice...: Copyright <img src='/emoticons/m5.gif' alt='applause' border='0' /> 2004 Tightline Computers, Inc
*** Function.: Copy the list of fields in the current, or specified, table to the clipboard
********************************************************************
LPARAMETERS tcTableLOCAL lcTable, lcALias, lcList, lnCnt, lcField, lnSelect
*** Did we get a table name
m.lnSelect = SELECT()
IF VARTYPE(tcTable) = "C" AND NOT EMPTY( tcTable )
	m.lcALias = JUSTSTEM( tcTable )
	*** If it's not used, open it  
	IF NOT USED( m.lcALias )
		IF FILE( FORCEEXT( tcTable, 'dbf' ))
			USE (tcTable) AGAIN IN 0 ALIAS (m.lcALias)
		ELSE
			_CLIPTEXT = ''
			RETURN
		ENDIF
	ENDIF

	*** And Select the Alias
	SELECT (m.lcALias)
ELSE
	*** Use whatever is currently selected  
	m.lcALias = ALIAS()ENDIF

	*** Get the list of field namesIF NOT EMPTY( lcAlias )
	m.lcList = ''
	FOR m.lnCnt = 1 TO FCOUNT()
		m.lcField = LOWER( ALLTRIM( FIELD( m.lnCnt )))
		m.lcList  = m.lcList + IIF( EMPTY( m.lcList ), "", ", " ) + m.lcField
	NEXT
	*** Add the alias name  
	_CLIPTEXT = m.lcList + CHR(13) + CHR(10) + "*** " + m.lcALias
ENDIF
*** Restore work area
SELECT (m.lnSelect)
RETURN

The second little utility is one that I call from a hot-key in my development environment to open an instance of Windows Explorer to the currently selected drive and directory. I confess that I find the inconsistent behavior of the windows that access the file system irritating. Some applications open a window to the last directory that was accessed, others simply use a standard (“My files”) or static directory (C:\ or “My Computer”) and others again do something which is apparently randomized. Generally, when working in VFP, if I need to access Windows Explorer I want to find a file that is either in the current working directory (typically the root directory of a project hierarchy) or in some specific related directory which I know the name of anyway (e.g. “D:\VFP90\COMMON”).
The RunExplorer procedure uses the ShellExecute() API function to open Windows Explorer to the required location and I call it using a simple ON KEY LABEL command so that it is available on my “F5” function key. It will accept a specific drive/directory as a parameter but the default behavior is to use the current VFP working directory. Here is the code for it:
********************************************************************
*** Name.....: RUNEXPLORER.PRG
*** Author...: Andy Kramek
*** Date.....: 25/09/2004
*** Notice...: Copyright <img src='/emoticons/m5.gif' alt='applause' border='0' /> 2004 Tightline Computers, Inc
*** Function.: Runs Windows Explorer with the specified directory selected
*** .........: Defaults to VFP current working directory if none passed
*****************************************************************
LPARAMETERS tcDirLOCAL ARRAY laDex[1]
LOCAL lcDir, lnDex, llIsLoaded, lcParms, lnRes
*** Default to current directory if nothing is passed in
IF VARTYPE( tcDir ) # "C" OR EMPTY( tcDir )
	lcDir = FULLPATH( CURDIR())
ELSE
	*** Default if specified directory does not exist
	IF NOT DIRECTORY( tcDir )
		lcDir = FULLPATH(CURDIR())
	ELSE
		lcDir = tcDir
	ENDIF
ENDIF
*** Make sure we have Shellexecute available
lnDex = ADLLS( laDex )
IF lnDex > 0  
	llIsLoaded = (ASCAN( laDex, 'shellexecute', 2, -1, 2, 15 ) > 0)
ELSE
	llIsLoaded = .F.
ENDIF

IF NOT llIsLoaded  
	*** Load the function
	DECLARE INTEGER ShellExecute IN shell32;
		INTEGER hwnd,; 
		STRING  lpOperation,; 
		STRING  lpFile,; 
		STRING  lpParameters,; 
		STRING  lpDirectory,; 
		INTEGER nShowCmd
ENDIF

*** Open Explorer to the correct location
lcParms = "/n,,/e," + lcDirlnRes 
= ShellExecute( 0, "open", 'explorer.exe', lcParms, "", 1 )
RETURN

Incidentally the same parameters (“/n,,/e,” + <path>) can be used in desktop shortcuts to open windows explorer to a more useful location than “my computer”. I usually set my shortcuts to use “D:\” since that is the root of my application drive and therefore the most likely place that I will want to start using Windows Explorer from – but you can choose anything.
The final little utility that I want to share is one that I use less often directly, but which is useful anyway. One of the things that I always do is to set an explicit search path in VFP (see my blog article on paths for details) but of course in order to specify a path you need to list all of the directories. It has always struck me as odd that Windows Explorer has no mechanism that will allow you to copy a list of names – so I wrote GetSubDirs() to create a comma-separated list of the first level sub-directories that exist under the specified root and push it on to the clipboard. Why just first level? Only because my standard project directory structure does not use anything deeper and I have no need to handle any additional complexity. The code could easily be made recursive to handle additional levels of sub-directories but I leave that as an exercise for the reader…J

********************************************************************
*** Name.....: GETSUBDIRS.PRG
*** Author...: Andy Kramek
*** Date.....: 23/09/2004
*** Notice...: Copyright <img src='/emoticons/m5.gif' alt='applause' border='0' /> 2004 Tightline Computers, Inc
*** Function.: Build a ";" separated list of SubDirectories and copy it to the clipboard
********************************************************************
LPARAMETERS tcRoot
LOCAL ARRAY laDirs[1]
LOCAL lcRoot, lcOrigDir, lnDirs, lnCnt, lcDir, lcList
*** We definitely need a root directory
IF EMPTY( m.tcRoot ) OR NOT DIRECTORY( m.tcRoot )
	m.lcRoot = GETDIR( CURDIR(), "Must specify a Root Directory", "Get SubDirs" )
	IF EMPTY(m.lcRoot)
		m.lcRoot = FULLPATH( CURDIR())
	ENDIF
ELSE
	m.lcRoot = FULLPATH( m.tcRoot )
ENDIF
*** Save the original location
m.lcOrigDir = FULLPATH( CURDIR() )
*** Switch to the specified directory
SET DEFAULT TO (m.lcRoot)
*** Now get a list of 1st level Sub_directories
m.lnDirs = ADIR( laDirs, '*.', 'D' )
IF m.lnDirs = 0
	_CLIPTEXT = ""
	SET DEFAULT TO (m.lcOrigDir)
	RETURN ""
ENDIF
*** We have at least one sub-directory
m.lcList = ''
FOR m.lnCnt = 1 TO m.lnDirs
	*** Ignore "." and ".." entries  
	m.lcDir = LOWER( ALLTRIM( CHRTRAN( m.laDirs[m.lnCnt, 1], '.', '')))
	IF EMPTY( m.lcDir )
		LOOP
	ENDIF
	*** Add the directory to the list  
	m.lcList = m.lcList + IIF( EMPTY( m.lcList ), '', ';' ) + m.lcDir
NEXT
*** Copy results to the clipboard and return the list
SET DEFAULT TO (m.lcOrigDir)
_CLIPTEXT = m.lcList
RETURN m.lcList

Published Sunday, June 18, 2006 1:05 PM by andykr

No comments:

Post a Comment

Writing better code (Part 1)

Writing better code (Part 1) As we all know, Visual FoxPro provides an extremely rich and varied development environment but sometimes to...