Spiff59 Posted May 14, 2009 Posted May 14, 2009 Ok, I'm not big on using .ini files, so haven't opted to mess with them much in the past.But, attempting to assist someone with a question in the forum here (topic) I threw together what seemed to be a simple example. The results I got were unexpected.A forum search didn't reveal any other idiots claiming a bug in IniRead(), so I'll post my question, and await the revelation as to what obvious, in-my-face, stupid blunder I've made.I assume everyone has a system.ini file in their Windows directory, and that it contains both a "timer" key and a "wave" key.Why then, below, does the read of "timer" succeed, but the read of "wave" fail?$Path = @WindowsDir & "\system.ini" $key1 = IniRead($Path, "drivers", "wave",'') MsgBox(1,"", $key1) $key1 = IniRead($Path, "drivers", "timer",'') MsgBox(1,"", $key1)
Xand3r Posted May 14, 2009 Posted May 14, 2009 you example works fine for me...(win7) Only two things are infinite, the universe and human stupidity, and i'm not sure about the former -Alber EinsteinPractice makes perfect! but nobody's perfect so why practice at all?http://forum.ambrozie.ro
Spiff59 Posted May 14, 2009 Author Posted May 14, 2009 (edited) you example works fine for me...(win7)This is very strange, the read of "wave", for me, returns an empty string, instead of "mmdrv.dll"(I'm running Windows XP Pro SP3)Edit: Hmm, I'll look over my system.ini file with WinHex and see if there are any peculiar characters hiding around that key...Edit2: There's nothing odd in my system.ini file. If I copy system.ini to system2.ini, then the script above works. So, my best wild-ass guess is that somehow IniRead() is not retrieving the actual system.ini file as it exists on disk, but instead is pulling something from the environment, or memory, and that copy of system.ini is missing the "wave" key. Maybe my X-FI Extreme soundcard driver temporarily removes that entry each time I boot my PC. Something is intercepting a direct read of the system.ini file by the IniRead() function. Edited May 14, 2009 by Spiff59
Achilles Posted May 14, 2009 Posted May 14, 2009 (edited) Your example works fine for me too... Windows Vista 64bit [drivers] wave=mmdrv.dll timer=timer.drvThis is my drivers section of the ini file Edited May 14, 2009 by Achilles My Programs[list][*]Knight Media Player[*]Multiple Desktops[*]Daily Comics[*]Journal[/list]
FinalVersion Posted May 14, 2009 Posted May 14, 2009 Wow, returns nothing on wave. Xp Pro Sp2. [center][+] Steam GUI [+][+] Clipboard Tool [+][+] System :: Uptime [+][+] StarCraft II Mouse Trap [+][/center]
Spiff59 Posted May 14, 2009 Author Posted May 14, 2009 (edited) In this example, IniRead() fails to retrieve the "wave" key, IniReadSection() fails to retrieve the "wave" key, but the line is displayed via the _FileReadToArray function: #include<file.au3> #include<array.au3> $Path = @WindowsDir & "\system.ini" $key1 = IniRead($Path, "drivers", "wave",'') MsgBox(1,"", $key1) $key1 = IniRead($Path, "drivers", "timer",'') MsgBox(1,"", $key1) $var = IniReadSection($Path, "drivers") For $i = 1 To $var[0][0] MsgBox(4096, "", "Key: " & $var[$i][0] & @CRLF & "Value: " & $var[$i][1]) Next Dim $array _FileReadToArray($Path, $array) _ArrayDisplay($array) So, using File... functions, instead of Ini... functions, will give me the actual data within the system.ini file on disk. Using the Ini... functions somehow presents some cached version, or version from memory. If this is how IniRead() and IniReadSection() behave (or Windows behaves), maybe it ought to be documented in the help file??? typo Edited May 14, 2009 by Spiff59
Spiff59 Posted May 14, 2009 Author Posted May 14, 2009 (edited) From MSDN (kernel32.dll's GetPrivateProfileString function):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\IniFileMappingThis mapping is likely if an application modifies system-component initialization files, such as Control.ini, System.ini, and Winfile.ini. In these cases, the function retrieves information from the registry, not from the initialization file; the change in the storage location has no effect on the function's behavior.The profile functions use the following steps to locate initialization information:Look in the registry for the name of the initialization file under the IniFileMapping key. Look for the section name specified by lpAppName. This will be a named value under the key that has the name of the initialization file, or a subkey with this name, or the name will not exist as either a value or subkey. If the section name specified by lpAppName is a named value, 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, 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, then there will be an unnamed value (shown as <No Name>) that specifies the default location in the registry where you will find the keys for the section. If there is no subkey or entry for the section name, then look for the actual initialization file 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.So, in the case of "system-component initialization files", IniRead() and IniReadSection() can not be trusted to return the values in the files as they exist on disk. Anyone think this worthy of comment in the help file?Edit: FYI, I found the following .ini files are mapped to the registry on my machine:Clock.inicontrol.iniImageFileExecutionOptions.iniKeyboardLayout.inimsacm.iniNtbackup.inintnet.iniregedt32.inischdpl32.inisystem.iniwin.iniwinfile.ini Edited May 14, 2009 by Spiff59
Authenticity Posted May 14, 2009 Posted May 14, 2009 (edited) Yup, function is looking in the registry to find that: drivers REG_SZ #SYS:Microsoft\Windows NT\CurrentVersion\drivers *think* goto HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\drivers ... to find that only - timer REG_SZ timer.drv exists;] Nothing is stopping you from implementing your own IniRead() function, for example you can do: Dim $sKey = __IniRead(@WindowsDir & '\system.ini', 'drivers', 'wave', '') ConsoleWrite($sKey & @LF) Func __IniRead($sFile, $sSection, $sKeyName, $sDefault) Local $hFile Local $sSrc Local $aMatch Local $hFile = FileOpen($sFile, 0) If $hFile = -1 Then Return SetError(1, 0, False) $sSrc = FileRead($hFile) FileClose($hFile) $aMatch = StringRegExp($sSrc, '(?m)(?s)^\[\Q' & $sSection & '\E\]\r\n(.*?(?=^\[|\z))', 1) If IsArray($aMatch) Then $aMatch = StringRegExp($aMatch[0], '(?m)^\Q' & $sKeyName & '\E\s*=(.*)', 1) If IsArray($aMatch) Then Return $aMatch[0] Return '' Else Return '' EndIf EndFunc Edited May 14, 2009 by Authenticity
Spiff59 Posted May 14, 2009 Author Posted May 14, 2009 (edited) Nothing is stopping you from implementing your own IniRead() function, for example you can do:Frankly, I have little interest in .ini files or the Ini... functions. I consider all the structure unnecessary bells-and-whistles and would rather just deal with simple text files. I am though a stickler for details and documentation, and when I come across something that doesn't behave as expected it piques my interest. I'd definately vote for a two-line addition to the .ini functions in the help file stating something like:Note: Certain system-component initialization files may be mapped to the registry, in these cases this function reads from, or writes to, the registry and does not access the .ini file on disk. Registry values may differ from those in the file.PS - I tested IniWrite() and IniWriteSection(), they write to the registry, and not the disk, for mapped .ini files. Edited May 14, 2009 by Spiff59
ResNullius Posted May 14, 2009 Posted May 14, 2009 (edited) Edit: FYI, I found the following .ini files are mapped to the registry on my machine:That would also explain something I found when trying to debug your problem:I copied system.ini to my scriptdir, changed the timer value to something else and it was still returning the old value.I then deleted all the sections in the copied system.ini and made my own, with it's own made-up section/values. I did a IniReadSectionNames, looped throug those to execute IniReadSection and _Array display the results and I got what (I thought) was in the original system.ini plus what was in my re-written copy...That's when I gave up and went to bed!Thanks for resolving this Spiff59. Edited May 14, 2009 by ResNullius
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now