GetTempPath and GetTempFileName


Visual Basic doesn’t give you much help with the common task of generating temporary files. The Windows API fixes the problem with the GetTempPath and GetTempFileName functions, but both suffer from C interfaces and need Basic wrappers. Here’s the raw GetTempFileName:

sFullName = String$(cMaxPath, 0)
Call GetTempFileName(“.”, “HC”, 0, sFullName)
sFullName = Left$(sFullName, InStr(sFullName, sNullChr) - 1)

The first argument is the directory for the temporary file, and the second is a prefix for this file. For the third argument, you can supply a number yourself, or you can use 0 as a signal to let Windows choose a random hexadecimal number for the last part of the filename. I can’t think of a reason to pass anything other than 0. The final argument is the buffer to receive the name. You should pass a buffer with the maximum file length for your operating system; you have no protection if you pass one that is too short. The return value is the number used for the last part of the name. I can’t imagine why you would need this. Unlike most API functions, this one doesn’t return the length of the string, so you have to find the length yourself by searching for the terminating null.


In other words, this is an inconvenient and somewhat dangerous function that takes one useless argument and returns garbage. The Basic wrapper GetTemp­­-File cleans it up, as shown on the next page.


The Problem of Existence


Testing for the existence of a file ought to be easy (and is in most languages), but it turns out to be one of the most annoying problems in Visual Basic. Don’t count on simple solutions like this:

fExist = (Dir$(sFullPath) <> sEmpty)

That statement works until you specify a file on an empty floppy or on a CD-ROM drive. Then you’re stuck in a message box. Here’s another common one:

fExist = FileLen(sFullPath)

It fails on 0-length files—uncommon but not unheard of. My theory is that the only reliable way to check for file existence in Basic (without benefit of API calls) is to use error trapping. I’ve challenged many Visual Basic programmers to give me an alternative, but so far no joy. Here’s the shortest way I know:

Function ExistFile(sSpec As String) As Boolean
On Error Resume Next
Call FileLen(sSpec)
ExistFile = (Err = 0)
End Function

This can’t be very efficient. Error trapping is designed to be fast for the no fail case, but this function is as likely to hit errors as not. Perhaps you’ll be the one to send me a Basic-only ExistFile function with no error trapping that I can’t break. Until then, here’s an API alternative:

Function ExistFileDir(sSpec As String) As Boolean
Dim af As Long
af = GetFileAttributes(sSpec)
ExistFileDir = (af <> -1)
End Function

I didn’t think there would be any way to break this one, but it turns out that certain filenames containing control characters are legal on Windows 95 but illegal on Windows NT. Or is it the other way around? Anyway, I have seen this function fail in situations too obscure to describe here.

I hate to waste brain cells on a function so trivial. But 99 percent effective existence tests aren’t good enough on a disk containing thousands of files.

‘ Get temp file for current directory
sFullName = GetTempFile(“VB”, “.”)

For the GetTempPath function, my GetTempDir wrapper simply returns the temporary directory. You can use it with GetTempFile:

‘ Get temp file for TEMP directory
sFullName = GetTempFile(“VB”, GetTempDir)

Of course, this is where you’ll usually want to put temporary files, so GetTemp­File assumes just that if you omit the second optional argument

‘ Get temp file for TEMP directory default
sFullName = GetTempFile(“VB”)

you can omit the prefix, too, if you don’t care what the file looks like:

‘ Get temp file for TEMP directory with no prefix
sFullName = GetTempFile

The calls to GetTempFile in the samples above generated C:\CURDIR\VB4B­.TMP, C:\TEMP\VB4C.TMP, C:\TEMP\VB4D.TMP, and C:\TEMP\4E.TMP. The filenames vary on different operating systems and different file systems. The only guarantee is that the generated file doesn’t currently exist. Windows will keep incrementing the number and trying the file until it finds a unique name. It’s up to you to open the file, process it, and—unless you want to be considered the crudest and most illiterate of programmers—delete it when you’re done.

This flame is directed at myself—in other words, it’s an apology for a crime I hope you will never commit (and that I will never repeat). I changed the interface of GetFullPath, SearchDirs, and GetTempFile. These functions did not use optional parameters in the C DLL versions described in the first edition of this book. Later I wrote a series of articles published on the Internet and in MSDN (also provided on the CD of this book) that described a different C++ version of the VBUTIL DLL. In this version, the functions used optional parameters—and that changed the design. The original parameter order matched the order of the API functions—a design decision that showed a lack of imagination. I “fixed” the order problem in the second version. The second DLL version was targeted at Visual Basic 4, which supported optional parameters only through Variants. But when I rewrote the functions in Basic for this edition, I changed to typed optional parame- ters. The bottom line is that if you’ve been a faithful follower of my writing, your code has been broken twice by incompatible versions of my functions. Fortunately, the interfaces of the wrapper functions—GetFullPath, GetFileBase, GetFileBaseExt, Get­File­Ext, and GetFileDir—haven’t changed, although their implemen- tation has. The moral of the story is: get your design right the first time. This is a good rule for all code, and it’s the law for ActiveX components. Since I’ve published VBCore as a component, I’d have to write new functions rather than change the old ones if I came up with more bright ideas.