Welcome To The Home Of The Visual FoxPro Experts  
home. signup. forum. archives. search. google. articles. downloads. faq. members. weblogs. file info. rss. print.

Recently I was working on an application where one of the requirements was that the number of users, accessing the application was delimited. There are quite a few tools available on internet to achieve just that but there was also the wish that this was completely written in VFP. In this article I share my solution to you all. Any comments are more than welcome, the more solid I can make this tool the better and I will keep you all informed, and by sharing our knowledge, we also support the community as a whole.

The third wish was that any settings, made by the users should be stored in INI files instead of the registry. This wish came explicitly from the network manager. The reason he gave for that, was his finding that uninstall not always removed the setting for an app in the registry.

The key to the solution
In this wish also lay the key to my solution. As you may all know, an INI file is nothing more but an ASCII file that one can read from and write to with two API functions, GetPrivateProfileString and WritePrivateProfileString.

The basic form of an INI file is like:

Under normal circumstances I would have used the two mentioned functions only.

However, try the following:
- Open two instances of VFP, both in the same directory. (hint, give each instance their own caption, making it easier to see which one you’re working in.)
- From one of them create a text-file with fcreate() like in:
lnHandle = Fcreate("SomeFile.txt")

- From the second instance try to do as follows:
?File("SomeFile.txt") &&returns .T.
lnHandle2 = fopen("SomeFile.txt") &&returns –1, indicating the file could not be opened.

- Close the first instance, DO NOT fclose() the txt file. This way you simulate a forced shutdown.
- Once more, from the second instance try the fopen() function. This time you should get a file handle with a positive number, indicating you opened the file. For the above TXT extension I used the INI extension. As a filename I use the sys(0) function where I extract the computer name and use that as a filename, like in:
lcFilename = sys(0)
lcFilename = strtran(lcFilename,”#”,”.”)
lcFilename = ALLTRIM(juststem(lcFilename))+”.INI”

For the purpose of my app I had two subdirectories. One was “USERINFO” the other was “USERSETTINGS”. In USERINFO I fcreate() the inifile. In that file I write some bogus info like:

Just to put the sysops mind at ease I write some info that an app might need. The file handle is stored as a property of the application object, as well as the filename (and path) for the inifile. When shutting down normally the INIfile in USERINFO is closed and any settings are written with WritePrivateProfileString in the INIfile in the USERSETTING directory.

The last step
The above info can be used to control the number of users that accesses the app concurrently while handling forced shutdowns as well. I did this as follows:
- The user starts the application through a shortcut on his/her desktop. The startup directory might be anywhere on the network.
- One table is opened, APPINFO with just one field cUSER (C 20).
- In the cUSER-field I place the machinename as given above.
- The app scans the table.
- Every record contains the name of an inifile in the USERINFO directory.
- The app tries to fopen() each one of them.
- If a valid filehandle is returned the file is thus no longer in use, otherwise it indicates that the file is in use by another user.
- The file is closed with fclose() and immediately erased, the record in APPINFO is deleted as well.

This way I achieve that users that could not shut down their app in a normal way (forced shutdown) are no longer blocking access to the app. (automatic cleanup).

- The number of non-deleted records is counted, if that number does not exceed the max allowed concurrent users (prop in application object) the two inifiles for the new user are respectively fcreate()’d and created with WritePrivateprofileString. In the APPINFO Table one more record is written with the computer name of the user’s machine. The table is closed.

When the user shuts down normally the record in the APPINFO table is deleted and the INIFile in the USERINFO directory is fclose()’d and deleted.

About API
As mentioned in this article there are, basically, two important function in the API one can use to handle INI files.
Those are GetPrivateProfileString and WritePrivateProfileString. Both are placed in the kernel32.dll. The syntax for declaring them both is:
DECLARE integer GetPrivateProfileString IN kernel32 string, string, string @, integer, string

- The first string point to the [section]
- The second parameter points to the key
- The third parameter is a string given as a replacement when the value of the key is not found.
- The fourth parameter is passed by reference (@) and is a buffer where the value of the key should be placed.
- The fifth parameter is a number indicating the size of the buffer
- The last parameter is the name AND PATH of the inifile.

So, in my app I used this function like:
lcBuffer = space(255)
?GetPrivateProfileString("section", "key", "Value not found", @lcBuffer, 255, "USERSETTING\"+goApp.cINIFILE)

As I mentioned before, I store the name of the INI file in my application object. I make that object a public object so that basically any value stored there can be accessed by the different components in the application.
DECLARE integer WritePrivateProfileString IN kernel32 string, string, string, string

- The first string point to the [section]
- The second parameter points to the key
- The third parameter is a string to write as the value of the key
- The last parameter is the name AND PATH of the inifile.

In my application I use this eg when closing forms. I read the top and left and write those to the inifile. The section name is then the name of the form. The numeric values are first converted to strings and written in the registry. When opening the form once more the info is first read from the ini and the values are stored in the form’s appropriate properties. This way the user preferences are saved. Of course you can store much more information in INI files.


Boudewijn Lutgerink Programming is one of the many hobbies of Boudewijn. He has worked with computers since 1985 and is the author of two books from Sybex. He has a weblog at http://weblogs.foxite.com/boudewijnlutgerink.


Brendon Cooper @ 6/30/2007 5:39:13 AM
This Is a great article thank you Boudewijn.

THe information regarding getPrivateProfileString was of particular use to me as now I can use an ini file when determining which database to open rather than hardcoding it in code. For testing purposes I always want to test on different databases, this was in the ini file it is very easy to change.

Thanks again

Brendon Cooper

Bilal @ 7/12/2007 7:59:19 AM
I am working on an application in which I have to restrict the numnber of users . I am using Asp.net 2.0 and SQL Server 2005. Can you help me in any manner . My personal e-mail Id is bilalwani9@gmail.com. I am awaiting for your response.
With Regards .

tuvia vinitsky @ 4/11/2008 7:48:33 AM
any chance you could post or send the actual code?


Your Name: 
Your Feedback: 

Spam Protection:
Enter the code shown: