The LFN Library for Clipper

The LFN Library for Clipper is a set of functions for handling long file names. It is an original work by Klas Engwall and placed in the public domain. Source code is included, so you can change anything you want to make it better suit your needs. The LIB files included in the distribution are compiled with Clipper 5.2e, so you may need to recompile the source code if your environment is different.

Download revision 1.11 here

Changes since the initial revision are listed here


Back in 1997 Ian "DrDebug" Day of Dark Black Software embarked on a project aiming at providing LFN support in Clipper. He intended to make it a patch which would allow normal usage of Clipper's existing file handling functions while getting the added LFN functionality.

Ian's approach was much more ambitious than my approach in this library, and his knowledge of the inner workings of Clipper and DOS is on an entirely different level than mine. So if Clipper had been more cooperative, his patch would have solved the LFN problem (except on NT4, which has no LFN support at all in the VDM) in a better way than I can offer.

But unfortunately Ian discovered that Clipper truncates file names after 16 characters, so in spite of all his work and clever solutions there was still a serious problem caused by Clipper itself. And judging from the readme files included in the last available beta version of his library (version 0.05), that was the reason he stopped development.

There have been many questions about LFN support on comp.lang.clipper in the years since, but as far as I know there is no other solution than Ian's DBLFN library publicly available. Until now (2002).

So what am I doing here?

Well, I found that there was need for some kind of solution that would give Clipper programmers access to file names longer than the 16 total characters that Clipper allows the users of Ian's DBLFN library. So I decided to look into it and see what could be done. And although my solution is not nearly as elegant as Ian's would have been if Clipper had let him do what he intended, it does handle file names of any length - within the OS limits, of course.

I spent a couple of weeks in June/July 2002 working on this project, and this is what I came up with. I call it the LFN Library. It has functions for creating, opening, renaming and erasing files with long names, for creating, renaming and erasing directories, for changing the current directory, for searching directories and a few other things. After the relase of the first beta version (Rev 0.90) on July 31 2002, I decided to migrate some routines to assembly in order to speed up executuion and also to try to add support for the extended get/set attributes DOS services (getting and setting file date, time and attributes). This support was added in Rev 0.91, and it was further extended in Rev 0.92, which also included a function for copying an existing file with a long file name to a new file. Rev 1.00 added a little more speed to that function by moving the read/write loop to assembly.

Over the years since 2002 I have added a few new functions to the library version I use internally and fixed a few minor things in the functions that existed in rev 1.00. After a question about LFN dbf files on comp.lang.clipper in September 2007 I decided to make a new public release of the things I have been added since 2002/2003.

The library comes with an almost complete demo application. It is included in the LIB file for convenience. It includes everything except the dbf/ntx/ndx handling functions. Just call it with "LFNdemo()" from your application and you will se what the LFN Library can do. LFNdemo() will restore the screen and the program settings when it returns control to your application.

The LFN Library did not originally have any direct support for using long file names with "Clipper's own" files, but this was changed in revision 1.10. Now it is possible to create and use dbf files with long file names as well as single index files (.ntx and .ndx). This is done by converting the long file names specified in the function calls to their short equivalents and then passing those short names on to Clipper's dbusearea(), dbcreateindex() and dbsetindex() functions respectively. Dbf files are created directly by calling the LFN library function LF_Fcreate() internally. There is still no support for cdx indexes.

How is it done and how does it work?

The LFN Library uses the 71xx DOS services under INT 21h that were introduced with Windows 95. For each function in the LFN Library, the underlying DOS service number is mentioned in the docs for the function in question. Ralf Brown's Interrupt List has all the details, if you are interested in looking them up. In order to call those services the library relies entirely on the extremely clever FT_Int86() function from the Nanforum Toolkit (written by Ted Means).

On the subject of LFN support, it should be said that using long file names on the command line in a DOS box is a completely separate thing from using long file names in DOS applications running on the same computer. The "DOS boxes", if I may use that term to refer to the command line of both CMD.EXE (on NT-class operating systems) and COMMAND.COM, are Win32 console applications which can handle long file names because they use the Win32 API.

This does not necessarily mean that there is also support for the DOS LFN services, which are what we must use from inside a DOS application to get the same functionality. And unfortunately Microsoft "forgot" to add that kind of support in the NTVDM (the NT Virtual DOS Machine) on NT-versions prior to Windows 2000, so there is no official way to use the LFN Library in that environment. However, there is something called "The LFN Services for Windows NT 4.0" which claims to solve this problem, at least to some extent. It is available for download at I should add that I have not tested that solution!

Functions included in the LFN Library

Long file name functions:
LF_7143Supp() Check if DOS function 7143h is supported
LF_ChDir()   Change current directory to an LFN directory
LF_ChkSubst()   Check the long path name of a SUBSTed drive
LF_CloseHand()   Close the FileFind handle after a file search
LF_CurDir()   Get the current long file name directory
LF_DbCreate()   Create a new dbf file with a long file name
LF_DbCreInd()   Create a new index file with a long file name
LF_DbSetInd()   Open an index file with a long file name
LF_DbUse()   Open a dbf file with a long file name
LF_Directory()   Find all files that match a name pattern
LF_Fcopy()   Copy a file with a long name to a new file
LF_Fcreate()   Create a new file with a long file name
LF_Ferase()   Erase a file with a long file name
LF_Ferror()   Return the error code for an LFN operation
LF_FindFirst()   Find the first file that matches a name pattern
LF_FindNext()   Find the next file that matches a name pattern
LF_Fopen()   Open an existing file with a long file name
LF_Frename()   Rename a file
LF_GetFAttr()   Get the attributes of a file
LF_GetFInfo()   Get the date/time, (physical) size and attributes of a file
LF_GetFSize()   Get the physical size of a file (including slack)
LF_GetFTime()   Get the creation time or last write or access time of a file
LF_GetHinfo()   Get the date/time, (real) size and attributes of a file, based on a file handle
LF_IsFile()   Determine if a file or a directory exists
LF_KillSubst()   Remove a SUBST
LF_LibVers()   Get the version number of the LFN Library
LF_MemoRead()   Read a disk file into a character string
LF_MemoWrit()   Write a character string to a disk file
LF_MkDir()   Create a directory with a long file name
LF_RmDir()   Remove a directory with a long file name
LF_SetFAttr()   Set the attributes of a file
LF_SetFTime()   Set the creation time or last write or access time of a file
LF_Subst()   Create a SUBST with a long path name
LF_Support()   Check if long file names are supported by the OS
LF_ToLong()   Get the canonical long name for a short file name
LF_ToShort()   Get the short name for a long file name or path
LF_VolInfo()   Get volume info for a drive
Demo application:
LFNdemo()   A complete demo application
The following functions are included in the Low Level Library (starting with Rev 1.00 of the LFN Library these functions have been moved to a separate library file).
Low level functions:
LL_FreeMem()   Free a memory block allocated by LL_Str2Mem()
LL_I2Attr()   Convert numerical file attributes to character
LL_IsBitOn()   Check if a certain bit in an integer is on or off
LL_IsProt()   Check if the application is running in protected mode
LL_LibVers()   Get the version number of the Low Level Library
LL_Mem2Str()   Copy a string from memory to a char variable
LL_Offset()   Get the offset of a protected mode memory selector
LL_Segment()   Get the segment of a protected mode memory selector
LL_Str2Mem()   Copy a string to a static memory location

Please note that the low level functions that were moved from the LFN Library to the Low Level Library were also renamed from LF_* to LL_*

More info about the latest changes can be found on the Changes page.

It is recommended that you start by checking if the operating system supports the LFN-specific DOS services and avoid using them if that is not the case. The function to use for that test is LF_Support(). In order to make your applications useful in both kinds of environments, you still have to provide support for "the old way" to handle files.

If you intend to use any of the extended get/set attributes functions, it is recommended that you also call LF_7143Supp() to find out if the operating system supports those functions. That support follows its own rules in addition to requiring support for the LFN DOS services in general (a total mess, in my humble opinion). It is probably safer to use LF_GetHInfo() instead to retrieve that kind of information since the DOS service used by it seems to have more consistent support in various Windows versions.

Although using most of the LFN Library functions only makes sense if the OS supports the LFN DOS services (for example, trying to create a file with a long name will definitely fail on "plain old DOS"), there are a few exceptions to that rule. LF_FindFirst(), LF_FindNext(), LF_Directory() and LF_IsFile() have support for both the LFN services and the corresponding SFN services that have been around since DOS 2.0, and they switch automatically between the two versions depending on the environment. This allows you to use the same routines to handle the result no matter which OS your application is running on.

What has been fixed since the initial version?

There is a lot of bit manipulation involved when retrieving file and directory information. File date, time, size and attributes are all encoded into bits, and sometimes they even span byte boundaries (for example, the hour component of a file time is located in bits 5-10 in a word). This makes it a little complicated to calculate the data for a file. There are some bit handling functions in Clipper, and there are some in the Nanforum Toolkit. But some of them are written in Clipper code with the speed penalties that imposes, and the collection is not complete. I have deliberately NOT used any functions from Clipper Tools (if there are any) since not everyone owns that library.

I have written a few additional file date/time specific bit manipulation routines to take care of what was missing in Clipper and Nanfor. In Rev 0.90 they were written in Clipper and therefore not very fast. In Rev 0.91 they were migrated from Clipper code to assembly, so they are now substantially faster than before.

The names of the internal functions were also changed to reduce the risk of clashes with functions in other libraries. They now all start with "_lf".

In Rev 0.92, there were no changes in the existing code. The only significant changes in the library since Rev 0.91 were the added functions that are mentioned on the Changes page and also briefly above.

In Rev 1.00, the most important change is the reorganization of the library in two separate LIB files. This will require an update of your link script(s) and possibly some function name changes in your code (if you use any of the functions listed under "Low Level functions" above).

Rev 1.00a adds a few new functions to the Low Level Library, but the LFN Library itself has not been changed.

Rev 1.10 adds support for dbf/ntx/ndx files and SUBSTed drives as well as LFN replacements for Clipper's memoread() and memowrit() functions. A few fixes and improvements to the already existing functions were also made.

Rev 1.11 fixes a typo in LF_Directory(), LF_CloseHand() and LF_IsFile() that prevented closing of the FileFind handle. The bug was introduced in Revision 1.10 so users of older versions are not affected.

Possible problems

I use Blinker, and I have personally only tested the LFN Library with version 5.1 of that linker. Other linkers may have problems with the LFN DOS services. Judging from what Ian Day says in one of his readme files, linking with Exospace could have been a potentional problem, but users of the LFN Library have reported that it works just fine with Exospace.

It is also a fact that the support for the extended get/set attributes DOS services (getting and setting file date, time and attributes) varies between the different Windows versions with the older versions being the worst. See the docs for the individual functions for more info.

What is needed in order to use the LFN Library?

Well, obviously you need the library itself :-). And your normal Clipper development tools, of course. If you do not use Clipper 5.2 you will have to recompile the source code with your Clipper version. In that case you also need a library manager such as Microsoft's LIB.EXE unless you decide that you can live with linking the OBJ files separately into your applications.

If you want to reassemble the assembly functions you also need MASM, the Microsoft Macro Assembler. I use version 5.1, but older versions should also work. I have tried version 6.1, but it is quite different from the earlier versions and may need changes in the source code. OBJ files for the assembly functions are included separately in case you do not have MASM but still want to rebuild the library from scratch.

Starting with Rev 1.00, the library itself is split into two different lib files. The directly LFN related functions are in LFN.LIB as before, but the low level functions previously labeled "Companion Functions" have been moved to the new LL.LIB file and at the same time been renamed from LF_* to LL_*. You must supply both library names (LFN.LIB and LL.LIB) in your link script! Rev 1.00 of the LFN Library requires Rev 1.00 or higher of the Low Level Library.

You also need the Nanforum Toolkit and its companion CPMI library. If you do not have them already, you can download them from the Oasis. CPMI.LIB is included in the Nanfor ZIP file.

So in order to use the LFN Library, these are the four libraries that you must add to your link script: LFN, LL, NANFOR and CPMI

If you need a Win32 Norton Guide viewer I can recommend Dave Pearson's WEG which you can download from his web site.

For recompiling the library source code, including the demo application, you also need the FTINT86.CH header file which comes with the Nanforum Toolkit, the LFNLIB.CH header file which is included in the LFN Library distribution and several standard Clipper header files.

It is recommended that you use #defines from LFNLIB.CH in your own applications when making calls to LFN Library functions.

Suggestions, bug reports etc

I got a few suggestions for enhancements after the first two beta versions were released. They resulted in the added support for the extended get/set services, the file copy function and some changes in the docs.

If you have any problems with the current version or any suggestions for making the library better, do not hesitate to tell me about them, either on comp.lang.clipper or via email at the address below.

However, do not expect me to fix things overnight. This is free software, and you have the source code in the distribution. So if you are in a hurry to get something fixed, feel free to do it yourself for your own needs. But please let me know what you did so I can fix it in the next release for everyone's benefit.

And please read the "Caution and Disclaimer" document!
Changes since the initial beta revision are listed here.




LFNLIB.ZIP Download the LFN Library
NFLIB305.ZIP Download the Nanforum Toolkit (from the Oasis)
WEG Download Dave Pearson's Norton Guide reader for Win32 (from Dave's website)
In case you want to talk to me about the LFN Library
(no general Clipper support questions please)
Back Go back to the Engwall InfoTech Clipper Pages main page

This document was last revised on 2009-07-30