?
Solved

Cached ini files?

Posted on 2002-04-30
21
Medium Priority
?
718 Views
Last Modified: 2008-03-03
Well - I've been playing with ini files for awhile... what I'm working on now is a program settings form which is SUPPOSED to let the user make changes to the main GUI.

I'm making use of the WritePrivateProfileString function built into the API.

-******Snip of Function*******_
Function putIniVal(ByVal strHeader As String, ByVal strKey As String, Value, ByVal strFilename As String) As Integer
'Write the value to the ini file.
    lngReturnValue = WritePrivateProfileString(strHeader, strKey, Value, strFilename)

-******ENDOF Snip of Function*******_

The putIniVal function *works* in that it does modify the ini file correctly. The problem I am having is that if I read the ini file right after I write to it, the changes are not reflected. If I close the program, restart the program the changes appear.



so if I do
putVal("Settings","GUICOLOR",255,My.ini")

and then

getinival("Settings","GUICOLOR",My.ini")

I don't get 255 I get the old value...

In my reading I found that win.ini is cached - are all ini's cached?

More importantly - what can I do to ensure that the putIniVal function makes the changes to the ini file immediately???


Cheers
Woot.
0
Comment
Question by:woottond
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 7
  • 5
21 Comments
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6981716
How do you know that file is wrote with putIniVal? you are reading it after modified and nothing happens!
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6981722
Optionally, you could use getsetting and savesetting to store values in registry instead.
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6981772
Also,
putVal("Settings","GUICOLOR",255,My.ini")
must be
("Settings","GUICOLOR","255","My.ini")

and then

getinival("Settings","GUICOLOR",My.ini")
must be
("Settings","GUICOLOR","My.ini")
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6981793
test:
Option Explicit
Private Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any, ByVal lpFileName As String) As Long
Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long


Private Sub Form_Load()
Dim ret As Long, buff As String
buff = Space$(255)
'change the value:
ret = WritePrivateProfileString("settings", "GUICOLOR", "124", "test.ini")


'retrieve new value:
ret = GetPrivateProfileString("settings", "GUICOLOR", vbNullString, buff, 255, "test.ini")
MsgBox Left$(buff, ret)

End Sub
0
 

Author Comment

by:woottond
ID: 6981948
my putinival is working - it stores the value to the file. I've verified this in two ways - one open the file after the put - the value is there. Also if I stop the program and restart it the value is correctly returned by getinival.

I'm not a big fan of the registry - I'd prefer to use an ini file.

The "" marks are not nessisary - as it is an implicit cast. I can add them - but it doesn't really matter.

Sorry to sound negative - I'm just trying to state things as clearly as possible...

My gut feeling is that the ini file is being cached. The file gets modified. The getinival gets the value from the cache, and won't get the new value until the cache is purged. The right symptoms anyhow.
0
 
LVL 16

Accepted Solution

by:
Richie_Simonetti earned 800 total points
ID: 6982055
Just try my little code and you see that new value is retrieved. I did a little ini file with value GUICOLOR=255, after that i changed it to 124 and, as you see in msgbox, it was changed.
Hope it helps
0
 
LVL 75

Expert Comment

by:Anthony Perkins
ID: 6982335
Windows INI files are cached for speed.  In order to re-cache make the following call (Going from memory and untested so please save before using):

WritePrivateProfileString "", "", "", "your ini file name goes here"

Anthony

0
 
LVL 75

Expert Comment

by:Anthony Perkins
ID: 6982345
Richie,

I suspect woottond is using Windows 95/98 or Me.  Take a look at the remarks for the WritePrivateProfileString function from MSDN:

<quote>
Windows 95/98/Me: The system keeps a cached version of Win.ini to improve performance. If all three parameters are NULL, the function flushes the cache. The function always returns FALSE after flushing the cache, regardless of whether the flush succeeds or fails.

A section in the initialization file must have the following form:

[section]
key=string
      .
      .
      .
If the lpFileName parameter does not contain a full path and file name for the file, WritePrivateProfileString searches the Windows directory for the file. If the file does not exist, this function creates the file in the Windows directory.

If lpFileName contains a full path and file name and the file does not exist, WritePrivateProfileString creates the file. The specified directory must already exist.

Windows NT/2000/XP: The system maps most .ini file references to the registry, using the mapping defined under the following registry key:

HKEY_LOCAL_MACHINE\Software\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping

Windows NT/Windows 2000 keeps a cache for the IniFileMapping registry key. Calling WritePrivateProfileStringW with the value of all arguments set to NULL will cause the system to refresh its cache of the IniFileMappingKey for the specified .ini file.

The profile functions use the following steps to locate initialization information:

Look in the registry for the name of the initialization file, say MyFile.ini, under IniFileMapping:
HKEY_LOCAL_MACHINE\Software\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping\myfile.ini

Look for the section name specified by lpAppName. This will be a named value under myfile.ini, or a subkey of myfile.ini, or will not exist.
If the section name specified by lpAppName is a named value under myfile.ini, then that value specifies where in the registry you will find the keys for the section.
If the section name specified by lpAppName is a subkey of myfile.ini, then named values under that subkey specify where in the registry you will find the keys for the section. If the key you are looking for does not exist as a named value, then there will be an unnamed value (shown as <No Name>) that specifies the default location in the registry where you will find the key.
If the section name specified by lpAppName does not exist as a named value or as a subkey under myfile.ini, then there will be an unnamed value (shown as <No Name>) under myfile.ini that specifies the default location in the registry where you will find the keys for the section.
If there is no subkey for MyFile.ini, or if there is no entry for the section name, then look for the actual MyFile.ini on the disk and read its contents.
When looking at values in the registry that specify other registry locations, there are several prefixes that change the behavior of the .ini file mapping:

! - this character forces all writes to go both to the registry and to the .ini file on disk.
# - this character causes the registry value to be set to the value in the Windows 3.1 .ini file when a new user logs in for the first time after setup.
@ - this character prevents any reads from going to the .ini file on disk if the requested data is not found in the registry.
USR: - this prefix stands for HKEY_CURRENT_USER, and the text after the prefix is relative to that key.
SYS: - this prefix stands for HKEY_LOCAL_MACHINE\SOFTWARE, and the text after the prefix is relative to that key.
An application using the WritePrivateProfileStringW function to enter .ini file information into the registry should follow these guidelines:

Ensure that no .ini file of the specified name exists on the system.
Ensure that there is a key entry in the registry that specifies the .ini file. This entry should be under the path HKEY_LOCAL_MACHINE\SOFTWARE \Microsoft\Windows NT\CurrentVersion\IniFileMapping.
Specify a value for that .ini file key entry that specifies a section. That is to say, an application must specify a section name, as it would appear within an .ini file or registry entry. Here is an example: [My Section].
For system files, specify SYS for an added value.
For application files, specify USR within the added value. Here is an example: "My Section: USR: App Name\Section". And, since USR indicates a mapping under HKEY_CURRENT_USER, the application should also create a key under HKEY_CURRENT_USER that specifies the application name listed in the added value. For the example just given, that would be "App Name".
After following the preceding steps, an application setup program should call WritePrivateProfileStringW with the first three parameters set to NULL, and the fourth parameter set to the INI file name. For example:
WritePrivateProfileStringW( NULL, NULL, NULL, L"appname.ini" );
Such a call causes the mapping of an .ini file to the registry to take effect before the next system reboot. The system rereads the mapping information into shared memory. A user will not have to reboot their computer after installing an application in order to have future invocations of the application see the mapping of the .ini file to the registry.
The following sample code illustrates the preceding guidelines and is based on several assumptions:

There is an application named App Name.
That application uses an .ini file named AppName.ini.
There is a section in the .ini file that we want to look like this:
[Section1]
  FirstKey = It all worked out okay.
  SecondKey = By golly, it works.
  ThirdKey = Another test.
The user will not have to reboot the system in order to have future invocations of the application see the mapping of the .ini file to the registry.
Here is the sample code :

 
// include files
#include <stdio.h>
#include <windows.h>
 
// a main function
main()
 
{
  // local variables
  CHAR inBuf[80];
  HKEY  hKey1, hKey2;
  DWORD  dwDisposition;
  LONG   lRetCode;
 
  // try to create the .ini file key
  lRetCode = RegCreateKeyEx ( HKEY_LOCAL_MACHINE,
                              "SOFTWARE\\Microsoft\\Windows NT
                               \\CurrentVersion\\IniFileMapping\\appname.ini",
                              0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,
                              NULL, &hKey1,
                              &dwDisposition);
 
  // if we failed, note it, and leave
  if (lRetCode != ERROR_SUCCESS){
    printf ("Error in creating appname.ini key\n");
    return (0) ;
    }
 
  // try to set a section value
  lRetCode = RegSetValueEx ( hKey1,
                             "Section1",
                             0,
                             REG_SZ,
                             "USR:App Name\\Section1",
                             20);
 
  // if we failed, note it, and leave
  if (lRetCode != ERROR_SUCCESS) {
    printf ( "Error in setting Section1 value\n");
    return (0) ;
    }
 
  // try to create an App Name key
  lRetCode = RegCreateKeyEx ( HKEY_CURRENT_USER,
                              "App Name",
                              0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,
                              NULL, &hKey2,
                              &dwDisposition);
 
  // if we failed, note it, and leave
  if (lRetCode != ERROR_SUCCESS) {
    printf ("Error in creating App Name key\n");
    return (0) ;
    }
 
  // force the system to re-read the mapping into shared memory
  //    so that future invocations of the application will see it
  //    without the user having to reboot the system
  WritePrivateProfileStringW( NULL, NULL, NULL, L"appname.ini" );
 
  // if we get this far, all has gone well
  // let's write some added values
  WritePrivateProfileString ("Section1", "FirstKey",
                             "It all worked out okay.", "appname.ini");
  WritePrivateProfileString ("Section1", "SecondKey",
                             "By golly, it works.", "appname.ini");
  WritePrivateProfileSection ("Section1", "ThirdKey = Another Test.",
                              "appname.ini");
 
  // let's test our work
  GetPrivateProfileString ("Section1", "FirstKey",
                           "Bogus Value: Get didn't work", inBuf, 80,
                           "appname.ini");
  printf ("%s", inBuf);
 
  // okay, we are outta here
  return(0);
 
}

</quote>
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6982495
I didn't know that for woottond was using win.ini!
0
 
LVL 75

Expert Comment

by:Anthony Perkins
ID: 6982521
Richie,

I see what you mean, but these are the remarks for
WritePrivateProfileString not WriteProfileString, so I can only assume that they simply copied the remarks from this last function and that it applies equally to "private" configuration files.

Anthony
0
 

Author Comment

by:woottond
ID: 6983101
I am using win98 and I'm not using win.ini for the record.

Reading post but its going to take me a few minutes to get through it all
0
 

Author Comment

by:woottond
ID: 6983144
Well - I've tried some more debugging...

Richie - your code is the pretty much the same as mine. The only differences being in the get function. So I have used both.

First in form 1:

put(val)

Close Form 1, open Form 2:

get(val)

DOESN'T WORK!

now if I do:

put(val)
get(val) <--- do this first

Close Form 1, open Form 2:

get(val)


Sooo - I'm still getting the feeling that it is being cached. What I don't understand is why getting from the ini file before I close the form makes it behave properly in the next form...

I've got a working work around but I hate that type of thing... there has to be a reason...

BTW - Richie was your get(val) on the same form as your put(val)? This seems to be the cause of my problems!

Cheers for the help thus far!
Woot.
0
 

Author Comment

by:woottond
ID: 6983152
spoke to soon

DOESN'T WORK

    put(val)
    get(val) <--- do this first

    Close Form 1, open Form 2:

    get(val)

DOES WORK

    put(val)
    msgbox get(val)

    Close Form 1, open Form 2:

    get(val)


WEIRD
0
 

Author Comment

by:woottond
ID: 6983200
spoke to soon

DOESN'T WORK

    put(val)
    get(val) <--- do this first

    Close Form 1, open Form 2:

    get(val)

DOES WORK

    put(val)
    msgbox get(val)

    Close Form 1, open Form 2:

    get(val)


WEIRD
0
 

Author Comment

by:woottond
ID: 6983232
Found it.

Richie - apologies - you were right...

the write API function does write to the cached file.

the read API function must read from cache. Why you ask?

well I wrote my own ini file reader. it reads from the file directly. BUT if you use the API write then it must wait to have the file updated before you can read from it.

so
APIput(val)
APIget(val) <-- works
nonAPIget(val) <-- doesn't

BUT
nonAPIput(val)
nonAPIget(val) <-- works

I'm going to write my own write method - but I have found the problem.

If you are going to use API write you must use API read OR flush the buffer.

Richie - here are the points - cheers mate.
0
 

Author Comment

by:woottond
ID: 6983234
Good call... =)

don't mix API with nonAPI. Lesson learned.
0
 
LVL 75

Expert Comment

by:Anthony Perkins
ID: 6983272
Again, the API functions on Windows 9.x use cache for speed. If you want to re-write the cache then the following call will do the trick:

WritePrivateProfileString "", "", "", "your ini file name goes here"

Anthony
0
 

Author Comment

by:woottond
ID: 6983306
Good call... =)

don't mix API with nonAPI. Lesson learned.
0
 

Author Comment

by:woottond
ID: 6983598
I didn't actually get the writePrivateProfileString "", "", "", "your ini file name goes here"

trick to work... I didn't spend much time with it as I got one of the fellas here to write a getinival (and he wrote it in the time it took to post my response... :)

anyhow - your answer is correct and I can post some points for you...

0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6983608
Thanks for "A" grade!
Tony, you know, 13 has a "bad mojo" ;)
0
 
LVL 75

Expert Comment

by:Anthony Perkins
ID: 6983734
woottond,

Thanks I appreciate that. It was not really necessary, I just thought you may have overlooked my message.

Richie,

Yeh, I noticed.  But then I "stole" some points from you
last week (Common Dialog box question), so what comes around goes around <g>

Anthony
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I’ve seen a number of people looking for examples of how to access web services from VB6.  I’ve been using a test harness I built in VB6 (using many resources I found online) that I use for small projects to work out how to communicate with web serv…
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…
Suggested Courses
Course of the Month13 days, 22 hours left to enroll

801 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question