|
When using ReadValues() on an empty [Section] or a Section which does not yet exist and one afterwards iterates through the elements of the array it seems there's alway one "empty" item.
Like in the following example:
Array arrProtocolNames = new Array[0];
protocolsIni.ReadValues("Protocols", ref arrProtocolNames);
foreach (string s in arrProtocolNames)
{
MessageBox.Show("Item found!:" + s + ".");
}
The MessageBox will show: Item found!:.
And therefore my ComboBoxes and Listboxes get filled with an empty entry in the first place.
As this is like the reference implementation mentioned here I would guess this is a bug from my (limited) point of view(?) If not: What's the official way to circumvent that?
edit: worked around it by using if (!s.Equals("")) in the foreach for now.
modified 12-Mar-12 15:46pm.
|
|
|
|
|
Thanks for the class , I was having problems with GetPrivateProfileString, you save me.
|
|
|
|
|
Your welcome
- aejw.com
|
|
|
|
|
Example:
[TestSection]
KeyName=我爱你
|
|
|
|
|
Unfortunately, this is a legacy class and only supports Ascii as the API commands only support ASCII (these API commands go all the way back to Windows 3.1)... In modern applications (unless INI is required), I advise using XML...
- aejw.com
|
|
|
|
|
[TestSection]
TestKey=2
Excuse me know someone say what is the role that I used to read me the value of the INI "2"?
|
|
|
|
|
Sorry for the late reply (i swear CP does not always send command notice emails)...
Role??? sorry, you have lost me a little, but...
aejw.cIni ini = new aejw.cIni("C:\\INIFile.ini");
string ret = ini.ReadValue("TheSection", "TestKey", "");
will read the 2 value...
- aejw.com
|
|
|
|
|
Hi,
Thank you for this great class. I'm very glad that it is fixed for returning string values with high ASCII chars in them. But i think that it has problems with high chars - like őűŐŰ -in the value name. It can't return the value (returns nothing) if the value name contains these chars, and ReadValues doesn't return all values in a section if some of their names contains these spec chars.
Could you check it please?
Thanks in advance.
-- modified at 13:27 Monday 20th March, 2006
|
|
|
|
|
Unfortunally őűŐŰ are not part of the ASCII table, ÒÓÔÕÖÙÚÛÜàáâãäåæçèéêë are, and as far as I have tested work correctly. Can you show / send me the code to have a look at?
----------------------------
aejw.com
|
|
|
|
|
Thanks for the reply. Unfortunatelly i've rewritten all the code to XML base to handle my special chars, so i don't have the old code now. I really loved the way your INI Class worked - great job man! - but i need those chars in my keynames. As i investigated i had a feeling that INI structure is just not capable to handle my needs by design. Anyhow, keep up the great work, and thanks for the answer!
|
|
|
|
|
Hi,
Nice code and article, but I'd like to comment on your naming convention: Hungarian notation was deprecated in .NET years ago. Please check out this link on MSDN.. (no pun intended)
|
|
|
|
|
Thanks... I really enjoyed reading the MSDN article you suggested. I am 100% self trained (thanks to the community) and would say my coding style and naming system is a mix of hundreds programmers that I have studyed / learnt from via code over the years.
I will have a look into changing my naming system before too long (I hope soon anyway, it will be a huge task as I have 100+ classes to convert).
----------------------------
Adam Woods
|
|
|
|
|
It seems not work with Unicode .ini files.
Thanks
|
|
|
|
|
I have yet to find a use for Unicode ini files (this class is mainly for leagacy support)... I would recommend using a xml interface which is virtually cabible of holding any format of data.
Although I fail to see the point, but at your request I will have a look into writing the text encoding detection routine before too long.
|
|
|
|
|
There is an error in ReadSections. StringBuilder doesn`t understand strings with zero chars inside. Look at http://archive.devx.com/dotnet/discussions/040902/cominterop.asp for example of using byte[] for strings buffer.
|
|
|
|
|
Thanks for reporting the bug this is now fixed and double checked for text encoding and char(0) support. Code Project should update the article with build 0019 soon.
----------------------------
Adam Woods
|
|
|
|
|
Hello all. I don't ever want to diminish work that others have done, so please don't take this as a slight to your efforts on this project.
There is an open-source project "out there" called Nini that allows developers to write configuration information to INI, .CONFIG, Registry, etc files. It works very well, and would be a good alternate to this implementation.
Overall, though, great work on this.
"Those that say a task is impossible shouldn't interrupt the ones who are doing it." - Chinese Proverb
|
|
|
|
|
Hi,
I'm also just want to point to other Open-Source project for handling INI files:
http://www.mentalis.org/soft/class.qpx?id=6
|
|
|
|
|
Hi,
here's a native version of an ini wrapper, without native PrivateProfileIni calls.
The first class wraps the ini file, the second class wraps each section.
You might want to do things differently, esp handling duplicate keys or sections, but I think you'll get the idea.
<br />
using System;<br />
using System.Text;<br />
using System.IO;<br />
using System.Collections;<br />
using System.Runtime;<br />
using System.Runtime.Serialization;<br />
using System.Xml ;<br />
<br />
using System.Diagnostics;<br />
<br />
namespace IniWrapper<br />
{<br />
[Serializable]<br />
public class IniFile : ICollection, IEnumerable<br />
{<br />
public static bool operator == (IniFile lhs, IniFile rhs)<br />
{<br />
foreach(IniSection section in lhs.m_sections)<br />
{<br />
if (!rhs.ContainsSection(section.Name)) <br />
return false;<br />
IniSection othersection = rhs[section.Name] as IniSection;<br />
if (section != othersection) return false;<br />
}<br />
<br />
return true;<br />
}<br />
public static bool operator != (IniFile lhs, IniFile rhs)<br />
{<br />
if (lhs == rhs) return false;<br />
return true;<br />
}<br />
<br />
<br />
public override bool Equals(object obj)<br />
{<br />
if (!(obj is IniFile))<br />
return false;<br />
return (this==(IniFile)obj);<br />
}<br />
<br />
<br />
<br />
public IniFile()<br />
{<br />
}<br />
<br />
public IniFile(string path)<br />
{<br />
m_path = path;<br />
Read();<br />
Parse();<br />
}<br />
private string m_path = "";<br />
private ArrayList m_lines;<br />
<br />
private ArrayList m_sections = new ArrayList();<br />
private Hashtable m_sectionlookup = new Hashtable();<br />
<br />
public void AddSection(IniSection section)<br />
{<br />
string name =section.Name;<br />
this[name]=section;<br />
}<br />
<br />
public IniSection this[string section_name]<br />
{<br />
get<br />
{<br />
if (m_sectionlookup.ContainsKey(section_name.ToLower()))<br />
return m_sections[(int)m_sectionlookup[section_name.ToLower()]] as IniSection;<br />
<br />
<br />
int id = m_sections.Add(new IniSection(section_name));<br />
m_sectionlookup.Add(section_name.ToLower(),id);<br />
return m_sections[id] as IniSection;<br />
<br />
}<br />
<br />
set<br />
{<br />
if (m_sectionlookup.ContainsKey(section_name.ToLower()))<br />
m_sections[(int)m_sectionlookup[section_name.ToLower()]] = value;<br />
else<br />
{<br />
int id = m_sections.Add(value);<br />
m_sectionlookup.Add(section_name.ToLower(),id);<br />
<br />
}<br />
}<br />
}<br />
<br />
public IniSection this[int section_id]<br />
{<br />
get<br />
{<br />
if (m_sectionlookup.ContainsKey(section_id))<br />
return m_sections[(int)m_sectionlookup[section_id]] as IniSection;<br />
return null;<br />
}<br />
}<br />
<br />
public bool ContainsSection(string section_name)<br />
{<br />
foreach(IniSection section in m_sections)<br />
{<br />
if (section.Name.ToLower()==section_name.ToLower()) return true;<br />
}<br />
return false;<br />
}<br />
<br />
public void Read(string path) <br />
{<br />
m_path = path;<br />
Read();<br />
}<br />
public void Read() <br />
{<br />
m_lines = new ArrayList();<br />
m_sections = new ArrayList();<br />
m_sectionlookup = new Hashtable();<br />
<br />
if (m_path.Length==0) return;<br />
if (!File.Exists(m_path)) throw new FileNotFoundException("Ini file not found",m_path);<br />
<br />
<br />
StreamReader sr = new StreamReader(m_path ,System.Text.Encoding.GetEncoding(1252));<br />
try <br />
{<br />
while (true)<br />
{<br />
string line = sr.ReadLine();<br />
if (line==null) break;<br />
if (line.Length>0)<br />
m_lines.Add(line);<br />
} <br />
} <br />
catch {}<br />
sr.Close();<br />
<br />
<br />
<br />
}<br />
<br />
public void Parse()<br />
{<br />
if (m_path.Length==0 || m_lines==null || m_lines.Count==0) return;<br />
IniSection section = null;<br />
m_sections.Clear();<br />
m_sectionlookup.Clear();<br />
for(int c=0;c<m_lines.Count;c++)<br />
{<br />
string line = m_lines[c].ToString().Trim();<br />
<br />
if (line != null && line.Length>0)<br />
{<br />
if (line.StartsWith("[") && (line.EndsWith("]")))<br />
{<br />
if (section != null)<br />
{<br />
m_sectionlookup.Add(section.Name.ToLower(),m_sections.Count);<br />
m_sections.Add(section);<br />
<br />
}<br />
section = new IniSection(line.Substring(1,line.Length-2).Trim());<br />
}<br />
else<br />
{<br />
int eq = line.IndexOf("=");<br />
if (section==null || eq<0)
{}<br />
else<br />
{<br />
string setting = line.Substring(0,eq).Trim();<br />
string val = line.Substring(eq+1).Trim();<br />
if (setting.Length>0) <br />
{<br />
if (!section.ContainsKey(setting))<br />
{<br />
section.Add(setting, val);<br />
} <br />
else
{<br />
string err = string.Format("Error reading Ini file {0} line {1}; possible duplicate value detected.",m_path,c);<br />
Trace.WriteLine(err);
<br />
if (section.ContainsKey(setting))<br />
{<br />
try {<br />
string oldval = section[setting];<br />
int aantal = Convert.ToInt32(oldval);<br />
int extra = Convert.ToInt32(val);<br />
int total = aantal + extra;<br />
section[setting] = total.ToString();<br />
Trace.WriteLine("WARNING: Numbers have been added. New total is " + total.ToString());<br />
} <br />
catch {<br />
string err2 = "FATAL: Duplicate Ini value in non-numeric section... Ini file invalid.";<br />
Trace.WriteLine(err2);<br />
throw new Exception(err2);<br />
}<br />
}<br />
<br />
}<br />
}<br />
}<br />
<br />
}<br />
}<br />
}<br />
if (section != null)<br />
{<br />
m_sectionlookup.Add(section.Name.ToLower(),m_sections.Count);<br />
m_sections.Add(section);<br />
}<br />
}<br />
<br />
public override string ToString()<br />
{<br />
StringBuilder sb = new StringBuilder();<br />
for (int c=0;c<m_sections.Count;c++)<br />
{<br />
sb.Append((m_sections[c] as IniSection).ToString());<br />
}<br />
return sb.ToString();<br />
<br />
}<br />
public void Save()<br />
{<br />
if (m_path.Length>0)<br />
this.Save(m_path,true);<br />
}<br />
public void Save(string path)<br />
{<br />
Save(path, false);<br />
}<br />
public void Save(string path, bool overwrite)<br />
{<br />
if (File.Exists(path) && !overwrite)<br />
throw new ArgumentException("File exists");<br />
if (File.Exists(path)) File.Delete(path);<br />
StreamWriter sw = new StreamWriter(path,false,System.Text.Encoding.UTF8);<br />
sw.Write(this.ToString());<br />
sw.Close();<br />
}<br />
<br />
public string Path<br />
{<br />
get<br />
{<br />
return m_path;<br />
}<br />
set<br />
{<br />
m_path = value;<br />
Read();<br />
}<br />
}<br />
<br />
<br />
<br />
<br />
public override int GetHashCode()<br />
{<br />
return m_sections.GetHashCode ();<br />
}<br />
<br />
#region ICollection Members<br />
<br />
public bool IsSynchronized<br />
{<br />
get<br />
{<br />
return m_sections.IsSynchronized;<br />
}<br />
}<br />
<br />
public int Count<br />
{<br />
get<br />
{<br />
return m_sections.Count;<br />
}<br />
}<br />
<br />
public void CopyTo(Array array, int index)<br />
{<br />
m_sections.CopyTo(array, index);<br />
}<br />
<br />
public object SyncRoot<br />
{<br />
get<br />
{<br />
return m_sections.SyncRoot;<br />
}<br />
}<br />
<br />
#endregion<br />
<br />
#region IEnumerable Members<br />
<br />
public IEnumerator GetEnumerator()<br />
{<br />
return m_sections.GetEnumerator();<br />
}<br />
<br />
#endregion<br />
}<br />
<br />
<br />
[Serializable]<br />
public class IniSection : System.Collections.Hashtable <br />
{<br />
private Hashtable m_sortorder = new Hashtable();<br />
private Hashtable m_upperlower = new Hashtable();<br />
<br />
public IniSection(string title) : base()<br />
{<br />
this.m_name=title;<br />
}<br />
<br />
public string this[string setting_name] <br />
{<br />
get<br />
{<br />
try <br />
{<br />
if (this.Contains(setting_name))<br />
{<br />
return base[setting_name].ToString();<br />
} <br />
else if (m_upperlower.ContainsKey(setting_name.ToLower())) <br />
{<br />
string name = m_upperlower[setting_name.ToLower()].ToString();<br />
if (this.ContainsKey(name))<br />
{<br />
string val = base[name].ToString();<br />
if (val==null || val.Length==0) return "";<br />
return val;<br />
} <br />
else<br />
return "";<br />
<br />
}<br />
else if (this.Contains(setting_name.ToLower()))<br />
{<br />
return base[setting_name.ToLower()].ToString();<br />
}<br />
else<br />
return "";<br />
} <br />
catch(Exception e)<br />
{<br />
Trace.WriteLine(string.Format("{0}\n{1}\n{2}\n{3}\n{4}",new string[] {setting_name, e.Message,e.Source,e.StackTrace,e.InnerException.Message}));<br />
}<br />
return "";<br />
}<br />
set<br />
{<br />
this.Add(setting_name, value);<br />
}<br />
}<br />
<br />
public override void Clear()<br />
{<br />
m_sortorder.Clear();<br />
m_upperlower.Clear();<br />
base.Clear ();<br />
}<br />
<br />
public string FindKey(string setting_value)<br />
{<br />
foreach(DictionaryEntry entry in this)<br />
{<br />
if (entry.Value.ToString()==setting_value)<br />
return entry.Key.ToString();<br />
else if (entry.Value.ToString().ToLower()==setting_value.ToLower())<br />
return entry.Key.ToString();<br />
<br />
}<br />
<br />
return null;<br />
}<br />
<br />
public string this[string setting_name, string default_value] <br />
{<br />
get<br />
{<br />
try <br />
{<br />
if (this.Contains(setting_name))<br />
{<br />
string val = base[setting_name].ToString();<br />
if (val==null || val.Length==0) return default_value;<br />
return val;<br />
}<br />
else if (m_upperlower.ContainsKey(setting_name.ToLower())) <br />
{<br />
string val = base[m_upperlower[setting_name.ToLower()].ToString()].ToString();<br />
if (val==null || val.Length==0) return default_value;<br />
return val;<br />
<br />
}<br />
else if (this.Contains(setting_name.ToLower()))<br />
{<br />
string val = base[setting_name.ToLower()].ToString();<br />
if (val==null || val.Length==0) return default_value;<br />
return val;<br />
}<br />
<br />
else<br />
return default_value;<br />
} <br />
catch<br />
{<br />
return default_value;<br />
}<br />
}<br />
set<br />
{<br />
this.Add(setting_name, value);<br />
}<br />
}<br />
<br />
<br />
public string this[int id]<br />
{<br />
get<br />
{<br />
if (m_sortorder.Contains(id))<br />
return this[m_sortorder[id].ToString()];<br />
else<br />
return null;<br />
}<br />
}<br />
<br />
<br />
public static bool operator == (IniSection lhs, IniSection rhs)<br />
{<br />
if ((object)lhs==null && (object)rhs==null) return true;<br />
if ((object)lhs==null || (object)rhs==null) return false;<br />
if (lhs.Name != rhs.Name) return false;<br />
foreach(DictionaryEntry entry in lhs)<br />
{<br />
if (!rhs.Contains(entry.Key)) return false;<br />
string val1=entry.Value.ToString();<br />
string val2=rhs[entry.Key].ToString();<br />
if (val1 != val2) return false;<br />
}<br />
return true;<br />
}<br />
<br />
public static bool operator != (IniSection lhs, IniSection rhs)<br />
{<br />
if (lhs==rhs) return false;<br />
return true;<br />
}<br />
<br />
<br />
public override bool Equals(object obj)<br />
{<br />
if (!(obj is IniSection))<br />
return false;<br />
return (this==(IniSection)obj);<br />
}<br />
<br />
<br />
public override string ToString()<br />
{<br />
System.Text.StringBuilder sb = new System.Text.StringBuilder();<br />
sb.AppendFormat("[{0}]{1}",m_name, Environment.NewLine);<br />
<br />
for(int c=0;c<m_sortorder.Count;c++)<br />
{<br />
string keyname = m_sortorder[c].ToString();<br />
string keyval = this[keyname].ToString();<br />
sb.AppendFormat("{0}={1}{2}",keyname,keyval, Environment.NewLine);<br />
}<br />
sb.AppendFormat("{0}{0}", Environment.NewLine);<br />
return sb.ToString();<br />
}<br />
<br />
<br />
<br />
public override void Add(object setting, object setting_value)<br />
{<br />
int item_id = this.Count;<br />
if (!this.ContainsKey(setting.ToString()))<br />
{<br />
m_sortorder.Add(item_id, setting.ToString());<br />
m_upperlower.Add(setting.ToString().ToLower(),setting.ToString());<br />
base.Add(setting.ToString(), setting_value.ToString());<br />
}<br />
else<br />
{<br />
this[setting]=setting_value;<br />
}<br />
}<br />
<br />
<br />
public string Name<br />
{<br />
get { return m_name; }<br />
}<br />
private string m_name;<br />
<br />
<br />
public override int GetHashCode()<br />
{<br />
return base.GetHashCode ();<br />
}<br />
<br />
<br />
<br />
}<br />
<br />
}<br />
<br />
|
|
|
|
|
Thanks, but... I think you fail to understand that INI / INF (Profile files, from the days of Windows 16bit) files don’t support multiple sections. Second this is a legacy support class (as noted). Also for anything more complex than a INI file, try a Xml interface!
----------------------------
Adam ej Woods
|
|
|
|
|
Hi am frome Sweden so i want to use åäö and other weird symbols in the ini file.
But it wont work.
"å" becomes "e" and "ä" becomes "v" and "ö" becomes "d". etc
|
|
|
|
|
|
Thanks
|
|
|
|
|
In you text you mentioned cINI0015.cs but that file is missing from you zip !?
Is it possible to get that file. Iam comming from the Delphi environment and like to use INI files.
Zola
|
|
|
|
|
Sorry for the typo, just use INI0016.cs, it will work just the same. I'll have the page updated as soon as I can.
----------------------------
Adam ej Woods
|
|
|
|