Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data / System / Data / OleDb / OledbConnectionStringbuilder.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="OleDbConnectionStringBuilder.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 //------------------------------------------------------------------------------
8
9     using System;
10     using System.Collections;
11     using System.Collections.Generic;
12     using System.ComponentModel;
13     using System.Data;
14     using System.Data.Common;
15     using System.Diagnostics;
16     using System.Globalization;
17     using System.Runtime.Serialization;
18     using System.Security.Permissions;
19     using System.Text;
20
21 namespace System.Data.OleDb {
22
23     [DefaultProperty("Provider")]
24     [RefreshPropertiesAttribute(RefreshProperties.All)]
25     [System.ComponentModel.TypeConverterAttribute(typeof(OleDbConnectionStringBuilder.OleDbConnectionStringBuilderConverter))]
26     public sealed class OleDbConnectionStringBuilder : DbConnectionStringBuilder {
27
28         private enum Keywords { // specific ordering for ConnectionString output construction
29 //          NamedConnection,
30             FileName,
31
32             Provider,
33             DataSource,
34             PersistSecurityInfo,
35
36             OleDbServices,
37         }
38
39         private static readonly string[] _validKeywords;
40         private static readonly Dictionary<string,Keywords> _keywords;
41
42         private string[] _knownKeywords;
43         private Dictionary<string,OleDbPropertyInfo> _propertyInfo;
44
45 //      private string _namedConnection   = DbConnectionStringDefaults.NamedConnection;
46         private string _fileName          = DbConnectionStringDefaults.FileName;
47
48         private string _dataSource        = DbConnectionStringDefaults.DataSource;
49         private string _provider          = DbConnectionStringDefaults.Provider;
50
51         private int _oleDbServices        = DbConnectionStringDefaults.OleDbServices;
52
53         private bool _persistSecurityInfo = DbConnectionStringDefaults.PersistSecurityInfo;
54
55         static OleDbConnectionStringBuilder() {
56             string[] validKeywords = new string[5];
57             validKeywords[(int)Keywords.DataSource]          = DbConnectionStringKeywords.DataSource;
58             validKeywords[(int)Keywords.FileName]            = DbConnectionStringKeywords.FileName;
59 //          validKeywords[(int)Keywords.NamedConnection]     = DbConnectionStringKeywords.NamedConnection;
60             validKeywords[(int)Keywords.OleDbServices]       = DbConnectionStringKeywords.OleDbServices;
61             validKeywords[(int)Keywords.PersistSecurityInfo] = DbConnectionStringKeywords.PersistSecurityInfo;
62             validKeywords[(int)Keywords.Provider]            = DbConnectionStringKeywords.Provider;
63             _validKeywords = validKeywords;
64
65             Dictionary<string,Keywords> hash = new Dictionary<string,Keywords>(9, StringComparer.OrdinalIgnoreCase);
66             hash.Add(DbConnectionStringKeywords.DataSource,                Keywords.DataSource);
67             hash.Add(DbConnectionStringKeywords.FileName,                  Keywords.FileName);
68 //          hash.Add(DbConnectionStringKeywords.NamedConnection,           Keywords.NamedConnection);
69             hash.Add(DbConnectionStringKeywords.OleDbServices,             Keywords.OleDbServices);
70             hash.Add(DbConnectionStringKeywords.PersistSecurityInfo,       Keywords.PersistSecurityInfo);
71             hash.Add(DbConnectionStringKeywords.Provider,                  Keywords.Provider);
72             Debug.Assert(5 == hash.Count, "initial expected size is incorrect");
73             _keywords = hash;
74         }
75
76         public OleDbConnectionStringBuilder() : this(null) {
77             _knownKeywords = _validKeywords;
78         }
79
80         public OleDbConnectionStringBuilder(string connectionString) : base() {
81             if (!ADP.IsEmpty(connectionString)) {
82                 ConnectionString = connectionString;
83             }
84         }
85
86         public override object this[string keyword] {
87             get {
88                 ADP.CheckArgumentNull(keyword, "keyword");
89                 object value;
90                 Keywords index;
91                 if (_keywords.TryGetValue(keyword, out index)) {
92                     value = GetAt(index);
93                 }
94                 else if (!base.TryGetValue(keyword, out value)) {
95                     Dictionary<string,OleDbPropertyInfo> dynamic = GetProviderInfo(Provider);
96                     OleDbPropertyInfo info = dynamic[keyword];
97                     value = info._defaultValue;
98                 }
99                 return value;
100             }
101             set {
102                 if (null != value) {
103                     ADP.CheckArgumentNull(keyword, "keyword");
104                     Keywords index;
105                     if (_keywords.TryGetValue(keyword, out index)) {
106                         switch(index) {
107                         case Keywords.DataSource:          DataSource = ConvertToString(value); break;
108                         case Keywords.FileName:            FileName = ConvertToString(value); break;
109 //                      case Keywords.NamedConnection:     NamedConnection = ConvertToString(value); break;
110                         case Keywords.Provider:            Provider = ConvertToString(value); break;
111
112                         case Keywords.OleDbServices:       OleDbServices = ConvertToInt32(value); break;
113
114                         case Keywords.PersistSecurityInfo: PersistSecurityInfo = ConvertToBoolean(value); break;
115                         default:
116                             Debug.Assert(false, "unexpected keyword");
117                             throw ADP.KeywordNotSupported(keyword);
118                         }
119                     }
120                     else {
121                         base[keyword] = value;
122                         ClearPropertyDescriptors();
123                     }
124                 }
125                 else {
126                     Remove(keyword);
127                 }
128             }
129         }
130
131         [DisplayName(DbConnectionStringKeywords.DataSource)]
132         [ResCategoryAttribute(Res.DataCategory_Source)]
133         [ResDescriptionAttribute(Res.DbConnectionString_DataSource)]
134         [RefreshPropertiesAttribute(RefreshProperties.All)]
135         // 
136         public string DataSource {
137             get { return _dataSource; }
138             set {
139                 SetValue(DbConnectionStringKeywords.DataSource, value);
140                 _dataSource = value;
141             }
142         }
143
144         [DisplayName(DbConnectionStringKeywords.FileName)]
145         [ResCategoryAttribute(Res.DataCategory_NamedConnectionString)]
146         [ResDescriptionAttribute(Res.DbConnectionString_FileName)]
147         [RefreshPropertiesAttribute(RefreshProperties.All)]
148         // 
149         [Editor("System.Windows.Forms.Design.FileNameEditor, " + AssemblyRef.SystemDesign, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing)]
150         public string FileName {
151             get { return _fileName; }
152             set {
153                 SetValue(DbConnectionStringKeywords.FileName, value);
154                 _fileName = value;
155             }
156         }
157
158 /*
159         [DisplayName(DbConnectionStringKeywords.NamedConnection)]
160         [ResCategoryAttribute(Res.DataCategory_NamedConnectionString)]
161         [ResDescriptionAttribute(Res.DbConnectionString_NamedConnection)]
162         [RefreshPropertiesAttribute(RefreshProperties.All)]
163         [TypeConverter(typeof(NamedConnectionStringConverter))]
164         public string NamedConnection {
165             get { return _namedConnection; }
166             set {
167                 SetValue(DbConnectionStringKeywords.NamedConnection, value);
168                 _namedConnection = value;
169             }
170         }
171 */
172         [DisplayName(DbConnectionStringKeywords.OleDbServices)]
173         [ResCategoryAttribute(Res.DataCategory_Pooling)]
174         [ResDescriptionAttribute(Res.DbConnectionString_OleDbServices)]
175         [RefreshPropertiesAttribute(RefreshProperties.All)]
176         [TypeConverter(typeof(OleDbConnectionStringBuilder.OleDbServicesConverter))]
177         public int OleDbServices {
178             get { return _oleDbServices; }
179             set {
180                 SetValue(DbConnectionStringKeywords.OleDbServices, value);
181                 _oleDbServices = value;
182             }
183         }
184
185         [DisplayName(DbConnectionStringKeywords.PersistSecurityInfo)]
186         [ResCategoryAttribute(Res.DataCategory_Security)]
187         [ResDescriptionAttribute(Res.DbConnectionString_PersistSecurityInfo)]
188         [RefreshPropertiesAttribute(RefreshProperties.All)]
189         public bool PersistSecurityInfo {
190             get { return _persistSecurityInfo; }
191             set {
192                 SetValue(DbConnectionStringKeywords.PersistSecurityInfo, value);
193                 _persistSecurityInfo = value;
194             }
195         }
196
197         [DisplayName(DbConnectionStringKeywords.Provider)]
198         [ResCategoryAttribute(Res.DataCategory_Source)]
199         [ResDescriptionAttribute(Res.DbConnectionString_Provider)]
200         [RefreshPropertiesAttribute(RefreshProperties.All)]
201         [TypeConverter(typeof(OleDbConnectionStringBuilder.OleDbProviderConverter))]
202         public string Provider {
203             get { return _provider; }
204             set {
205                 SetValue(DbConnectionStringKeywords.Provider, value);
206                 _provider = value;
207                 RestartProvider();
208             }
209         }
210
211         public override ICollection Keys {
212             get {
213                 string[] knownKeywords = _knownKeywords;
214                 if (null == knownKeywords) {
215
216                     Dictionary<string,OleDbPropertyInfo> dynamic = GetProviderInfo(Provider);
217                     if (0 < dynamic.Count) {
218                         knownKeywords = new string[_validKeywords.Length + dynamic.Count];
219                         _validKeywords.CopyTo(knownKeywords, 0);
220                         dynamic.Keys.CopyTo(knownKeywords, _validKeywords.Length);
221                     }
222                     else {
223                         knownKeywords = _validKeywords;
224                     }
225
226                     int count = 0;
227                     foreach(string keyword in base.Keys) {
228                         bool flag = true;
229                         foreach(string s in knownKeywords) {
230                             if (StringComparer.OrdinalIgnoreCase.Equals(s, keyword)) {
231                                 flag = false;
232                                 break;
233                             }
234                         }
235                         if (flag) {
236                             count++;
237                         }
238                     }
239                     if (0 < count) {
240                         string[] tmp = new string[knownKeywords.Length + count];
241                         knownKeywords.CopyTo(tmp, 0);
242
243                         int index = knownKeywords.Length;
244                         foreach(string keyword in base.Keys) {
245                             bool flag = true;
246                             foreach(string s in knownKeywords) {
247                                 if (StringComparer.OrdinalIgnoreCase.Equals(s, keyword)) {
248                                     flag = false;
249                                     break;
250                                 }
251                             }
252                             if (flag) {
253                                 tmp[index++] = keyword;
254                             }
255                         }
256                         knownKeywords = tmp;
257                     }
258                     _knownKeywords = knownKeywords;
259                 }
260                 return new System.Data.Common.ReadOnlyCollection<string>(knownKeywords);
261             }
262         }
263
264         public override bool ContainsKey(string keyword) {
265             ADP.CheckArgumentNull(keyword, "keyword");
266             return _keywords.ContainsKey(keyword) || base.ContainsKey(keyword);
267         }
268
269         private static bool ConvertToBoolean(object value) {
270             return DbConnectionStringBuilderUtil.ConvertToBoolean(value);
271         }
272         private static int ConvertToInt32(object value) {
273             return DbConnectionStringBuilderUtil.ConvertToInt32(value);
274         }
275         private static string ConvertToString(object value) {
276             return DbConnectionStringBuilderUtil.ConvertToString(value);
277         }
278
279         public override void Clear() {
280             base.Clear();
281             for(int i = 0; i < _validKeywords.Length; ++i) {
282                 Reset((Keywords)i);
283             }
284             base.ClearPropertyDescriptors();
285             _knownKeywords = _validKeywords;
286         }
287
288         private object GetAt(Keywords index) {
289             switch(index) {
290             case Keywords.DataSource:          return DataSource;
291             case Keywords.FileName:            return FileName;
292 //          case Keywords.NamedConnection:     return NamedConnection;
293             case Keywords.OleDbServices:       return OleDbServices;
294             case Keywords.PersistSecurityInfo: return PersistSecurityInfo;
295             case Keywords.Provider:            return Provider;
296             default:
297                 Debug.Assert(false, "unexpected keyword");
298                 throw ADP.KeywordNotSupported(_validKeywords[(int)index]);
299             }
300         }
301
302         public override bool Remove(string keyword) {
303             ADP.CheckArgumentNull(keyword, "keyword");
304             bool value = base.Remove(keyword);
305
306             Keywords index;
307             if (_keywords.TryGetValue(keyword, out index)) {
308                 Reset(index);
309             }
310             else if (value) {
311                 ClearPropertyDescriptors();
312             }
313             return value;
314         }
315
316         private void Reset(Keywords index) {
317             switch(index) {
318             case Keywords.DataSource:
319                 _dataSource = DbConnectionStringDefaults.DataSource;
320                 break;
321             case Keywords.FileName:
322                 _fileName = DbConnectionStringDefaults.FileName;
323                 RestartProvider();
324                 break;
325 //          case Keywords.NamedConnection:
326 //             _namedConnection = DbConnectionStringDefaults.NamedConnection;
327 //              break;
328             case Keywords.OleDbServices:
329                 _oleDbServices = DbConnectionStringDefaults.OleDbServices;
330                 break;
331             case Keywords.PersistSecurityInfo:
332                 _persistSecurityInfo = DbConnectionStringDefaults.PersistSecurityInfo;
333                 break;
334             case Keywords.Provider:
335                 _provider = DbConnectionStringDefaults.Provider;
336                 RestartProvider();
337                 break;
338              default:
339                 Debug.Assert(false, "unexpected keyword");
340                 throw ADP.KeywordNotSupported(_validKeywords[(int)index]);
341             }
342         }
343
344         private new void ClearPropertyDescriptors() {
345             base.ClearPropertyDescriptors();
346             _knownKeywords = null;
347         }
348
349         private void RestartProvider() {
350             ClearPropertyDescriptors();
351             _propertyInfo = null;
352         }
353
354         private void SetValue(string keyword, bool value) {
355             base[keyword] = value.ToString((System.IFormatProvider)null);
356         }
357         private void SetValue(string keyword, int value) {
358             base[keyword] = value.ToString((System.IFormatProvider)null);
359         }
360         private void SetValue(string keyword, string value) {
361             ADP.CheckArgumentNull(value, keyword);
362             base[keyword] = value;
363         }
364
365         public override bool TryGetValue(string keyword, out object value) {
366             ADP.CheckArgumentNull(keyword, "keyword");
367             Keywords index;
368             if (_keywords.TryGetValue(keyword, out index)) {
369                 value = GetAt(index);
370                 return true;
371             }
372             else if (!base.TryGetValue(keyword, out value)) {
373                 Dictionary<string,OleDbPropertyInfo> dynamic = GetProviderInfo(Provider);
374                 OleDbPropertyInfo info;
375                 if (dynamic.TryGetValue(keyword, out info)) {
376                     value = info._defaultValue;
377                     return true;
378                 }
379                 return false;
380             }
381             return true;
382         }
383
384         private Dictionary<string,OleDbPropertyInfo> GetProviderInfo(string provider) {
385             Dictionary<string,OleDbPropertyInfo> providerInfo = _propertyInfo;
386             if (null == providerInfo) {
387                 providerInfo = new Dictionary<string,OleDbPropertyInfo>(StringComparer.OrdinalIgnoreCase);
388                 if (!ADP.IsEmpty(provider)) {
389                     Dictionary<string,OleDbPropertyInfo> hash = null;
390                     try {
391                         StringBuilder builder = new StringBuilder();
392                         AppendKeyValuePair(builder, DbConnectionStringKeywords.Provider, provider);
393                         OleDbConnectionString constr = new OleDbConnectionString(builder.ToString(), true);
394                         constr.CreatePermissionSet().Demand();
395
396                         // load provider without calling Initialize or CreateDataSource
397                         using(OleDbConnectionInternal connection = new OleDbConnectionInternal(constr, (OleDbConnection)null)) {
398
399                             // get all the init property information for the provider
400                             hash = connection.GetPropertyInfo(new Guid[] { OleDbPropertySetGuid.DBInitAll });
401                             foreach(KeyValuePair<string,OleDbPropertyInfo> entry in hash) {
402                                 Keywords index;
403                                 OleDbPropertyInfo info = entry.Value;
404                                 if (!_keywords.TryGetValue(info._description, out index)) {
405                                     if ((OleDbPropertySetGuid.DBInit == info._propertySet) &&
406                                             ((ODB.DBPROP_INIT_ASYNCH == info._propertyID) ||
407                                              (ODB.DBPROP_INIT_HWND == info._propertyID) ||
408                                              (ODB.DBPROP_INIT_PROMPT == info._propertyID))) {
409                                         continue; // skip this keyword
410                                     }
411                                     providerInfo[info._description] = info;
412                                 }
413                             }
414
415                             // what are the unique propertysets?
416                             List<Guid> listPropertySets= new List<Guid>();
417                             foreach(KeyValuePair<string,OleDbPropertyInfo> entry in hash) {
418                                 OleDbPropertyInfo info = entry.Value;
419                                 if (!listPropertySets.Contains(info._propertySet)) {
420                                     listPropertySets.Add(info._propertySet);
421                                 }
422                             }
423                             Guid[] arrayPropertySets = new Guid[listPropertySets.Count];
424                             listPropertySets.CopyTo(arrayPropertySets, 0);
425
426                             // get all the init property values for the provider
427                             using(PropertyIDSet propidset = new PropertyIDSet(arrayPropertySets)) {
428                                 using(IDBPropertiesWrapper idbProperties = connection.IDBProperties()) {
429
430                                     OleDbHResult hr;
431                                     using(DBPropSet propset = new DBPropSet(idbProperties.Value, propidset, out hr)) {
432                                         // VSDD 671375: OleDbConnectionStringBuilder is ignoring/hiding potential errors of OLEDB provider when reading its properties information
433                                         if (0 <= (int)hr) {
434                                             int count = propset.PropertySetCount;
435                                             for(int i = 0; i < count; ++i) {
436                                                 Guid propertyset;
437                                                 tagDBPROP[] props = propset.GetPropertySet(i, out propertyset);
438
439                                                 // attach the default property value to the property info
440                                                 foreach(tagDBPROP prop in props) {
441
442                                                     foreach(KeyValuePair<string,OleDbPropertyInfo> entry in hash) {
443                                                         OleDbPropertyInfo info = entry.Value;
444                                                         if ((info._propertyID == prop.dwPropertyID) && (info._propertySet == propertyset)) {
445                                                             info._defaultValue = prop.vValue;
446
447                                                             if (null == info._defaultValue) {
448                                                                 if (typeof(string) == info._type) {
449                                                                     info._defaultValue = "";
450                                                                 }
451                                                                 else if (typeof(Int32) == info._type) {
452                                                                     info._defaultValue = 0;
453                                                                 }
454                                                                 else if (typeof(Boolean) == info._type) {
455                                                                     info._defaultValue = false;
456                                                                 }
457                                                             }
458                                                         }
459                                                     }
460                                                 }
461                                             }
462                                         }
463                                     }
464                                 }
465                             }
466                         }
467                     }
468                     catch(System.InvalidOperationException e) {
469                         ADP.TraceExceptionWithoutRethrow(e);
470                     }
471                     catch(System.Data.OleDb.OleDbException e) {
472                         ADP.TraceExceptionWithoutRethrow(e);
473                     }
474                     catch(System.Security.SecurityException e) {
475                         ADP.TraceExceptionWithoutRethrow(e);
476                     }
477                 }
478                 _propertyInfo = providerInfo;
479             }
480             return providerInfo;
481         }
482
483         protected override void GetProperties(Hashtable propertyDescriptors) {
484             Dictionary<string,OleDbPropertyInfo> providerInfo = GetProviderInfo(Provider);
485             if (0 < providerInfo.Count) {
486
487                 foreach(OleDbPropertyInfo info in providerInfo.Values) {
488                     Keywords index;
489                     if (!_keywords.TryGetValue(info._description, out index)) { // not a strongly typed property
490
491                         bool isReadOnly = false;
492                         bool refreshOnChange = false;
493                         Attribute[] attributes;
494                         if (OleDbPropertySetGuid.DBInit == info._propertySet) {
495                             switch(info._propertyID) {
496 #if DEBUG
497                             case ODB.DBPROP_AUTH_PERSIST_SENSITIVE_AUTHINFO:
498                             case ODB.DBPROP_INIT_ASYNCH:
499                             case ODB.DBPROP_INIT_DATASOURCE:
500                             case ODB.DBPROP_INIT_HWND:
501                             case ODB.DBPROP_INIT_OLEDBSERVICES:
502                                 Debug.Assert(false, "should be handled via strongly typed property");
503                                 goto default;
504 #endif
505                             case ODB.DBPROP_INIT_CATALOG:
506                             case ODB.DBPROP_INIT_LOCATION:
507                                 attributes = new Attribute[] {
508                                     BrowsableAttribute.Yes,
509                                     new ResCategoryAttribute(Res.DataCategory_Source),
510                                     RefreshPropertiesAttribute.All,
511                                 };
512                                 break;
513                             case ODB.DBPROP_INIT_TIMEOUT:
514                             case ODB.DBPROP_INIT_GENERALTIMEOUT:
515                                 attributes = new Attribute[] {
516                                     BrowsableAttribute.Yes,
517                                     new ResCategoryAttribute(Res.DataCategory_Initialization),
518                                     RefreshPropertiesAttribute.All,
519                                 };
520                                 break;
521                             // 'Password' & 'User ID' will be readonly if 'Integrated Security' exists
522                             case ODB.DBPROP_AUTH_PASSWORD:
523                                 attributes = new Attribute[] {
524                                     BrowsableAttribute.Yes,
525                                     PasswordPropertyTextAttribute.Yes,
526                                     new ResCategoryAttribute(Res.DataCategory_Security),
527                                     RefreshPropertiesAttribute.All,
528                                 };
529                                 isReadOnly = ContainsKey(DbConnectionStringKeywords.IntegratedSecurity);
530                                 refreshOnChange = true;
531                                 break;
532                             case ODB.DBPROP_AUTH_USERID:
533                                 attributes = new Attribute[] {
534                                     BrowsableAttribute.Yes,
535                                     new ResCategoryAttribute(Res.DataCategory_Security),
536                                     RefreshPropertiesAttribute.All,
537                                 };
538                                 isReadOnly = ContainsKey(DbConnectionStringKeywords.IntegratedSecurity);
539                                 refreshOnChange = true;
540                                 break;
541                             case ODB.DBPROP_AUTH_CACHE_AUTHINFO:
542                             case ODB.DBPROP_AUTH_ENCRYPT_PASSWORD:
543                             case ODB.DBPROP_AUTH_INTEGRATED:
544                             case ODB.DBPROP_AUTH_MASK_PASSWORD:
545                             case ODB.DBPROP_AUTH_PERSIST_ENCRYPTED:
546                                 attributes = new Attribute[] {
547                                     BrowsableAttribute.Yes,
548                                     new ResCategoryAttribute(Res.DataCategory_Security),
549                                     RefreshPropertiesAttribute.All,
550                                 };
551                                 refreshOnChange = (ODB.DBPROP_AUTH_INTEGRATED == info._propertyID);
552                                 break;
553
554                             case ODB.DBPROP_INIT_BINDFLAGS:
555                             case ODB.DBPROP_INIT_IMPERSONATION_LEVEL:
556                             case ODB.DBPROP_INIT_LCID:
557                             case ODB.DBPROP_INIT_MODE:
558                             case ODB.DBPROP_INIT_PROTECTION_LEVEL:
559                             case ODB.DBPROP_INIT_PROVIDERSTRING:
560                             case ODB.DBPROP_INIT_LOCKOWNER:
561                                 attributes = new Attribute[] {
562                                     BrowsableAttribute.Yes,
563                                     new ResCategoryAttribute(Res.DataCategory_Advanced),
564                                     RefreshPropertiesAttribute.All,
565                                 };
566                                 break;
567                             default:
568                                 Debug.Assert(false, "new standard propertyid");
569                                 attributes = new Attribute[] {
570                                     BrowsableAttribute.Yes,
571                                     RefreshPropertiesAttribute.All,
572                                 };
573                                 break;
574                             }
575                         }
576                         else if (info._description.EndsWith(" Provider", StringComparison.OrdinalIgnoreCase)) {
577                             attributes = new Attribute[] {
578                                 BrowsableAttribute.Yes,
579                                 RefreshPropertiesAttribute.All,
580                                 new ResCategoryAttribute(Res.DataCategory_Source),
581                                 new TypeConverterAttribute(typeof(OleDbConnectionStringBuilder.OleDbProviderConverter)),
582                             };
583                             refreshOnChange = true;
584                         }
585                         else {
586                             attributes = new Attribute[] {
587                                 BrowsableAttribute.Yes,
588                                 RefreshPropertiesAttribute.All,
589                                 new CategoryAttribute(Provider),
590                             };
591                         }
592
593                         DbConnectionStringBuilderDescriptor descriptor = new DbConnectionStringBuilderDescriptor(info._description,
594                             typeof(OleDbConnectionStringBuilder), info._type, isReadOnly, attributes);
595                         descriptor.RefreshOnChange = refreshOnChange;
596
597                         propertyDescriptors[info._description] = descriptor;
598                     }
599                     // else strongly typed property already exists, i.e. DataSource
600                 }
601             }
602             base.GetProperties(propertyDescriptors);
603         }
604
605         private sealed class OleDbProviderConverter : StringConverter {
606
607             private const int DBSOURCETYPE_DATASOURCE_TDP = 1;
608             private const int DBSOURCETYPE_DATASOURCE_MDP = 3;
609
610             private StandardValuesCollection _standardValues;
611
612             // converter classes should have public ctor
613             public OleDbProviderConverter() {
614             }
615
616             public override bool GetStandardValuesSupported(ITypeDescriptorContext context) {
617                 return true;
618             }
619
620             public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) {
621                 return false;
622             }
623
624             public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) {
625                 StandardValuesCollection dataSourceNames = _standardValues;
626                 if (null == _standardValues) {
627                     // Get the sources rowset for the SQLOLEDB enumerator
628                     DataTable table = (new OleDbEnumerator()).GetElements();
629
630                     DataColumn column2 = table.Columns["SOURCES_NAME"];
631                     DataColumn column5 = table.Columns["SOURCES_TYPE"];
632                     //DataColumn column4 = table.Columns["SOURCES_DESCRIPTION"];
633
634                     System.Collections.Generic.List<string> providerNames = new System.Collections.Generic.List<string>(table.Rows.Count);
635                     foreach(DataRow row in table.Rows) {
636                         int sourceType = (int)row[column5];
637                         if (DBSOURCETYPE_DATASOURCE_TDP == sourceType || DBSOURCETYPE_DATASOURCE_MDP == sourceType) {
638                             string progid = (string)row[column2];
639                             if (!OleDbConnectionString.IsMSDASQL(progid.ToLower(CultureInfo.InvariantCulture))) {
640                                 if (0 > providerNames.IndexOf(progid)) {
641                                     providerNames.Add(progid);
642                                 }
643                             }
644                         }
645                     }
646
647                     // Create the standard values collection that contains the sources
648                     dataSourceNames = new StandardValuesCollection(providerNames);
649                     _standardValues = dataSourceNames;
650                 }
651                 return dataSourceNames;
652             }
653         }
654
655         [Flags()] internal enum OleDbServiceValues : int {
656             DisableAll              = unchecked((int)0x00000000),
657             ResourcePooling         = unchecked((int)0x00000001),
658             TransactionEnlistment   = unchecked((int)0x00000002),
659             ClientCursor            = unchecked((int)0x00000004),
660             AggregationAfterSession = unchecked((int)0x00000008),
661             EnableAll               = unchecked((int)0xffffffff),
662             Default                 = ~(ClientCursor | AggregationAfterSession),
663         };
664
665         internal sealed class OleDbServicesConverter : TypeConverter {
666
667             private StandardValuesCollection _standardValues;
668
669             // converter classes should have public ctor
670             public OleDbServicesConverter() : base() {
671             }
672
673             public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
674                 // Only know how to convert from a string
675                 return ((typeof(string) == sourceType) || base.CanConvertFrom(context, sourceType));
676             }
677
678             public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
679                 string svalue = (value as string);
680                 if (null != svalue) {
681                     Int32 services;
682                     if(Int32.TryParse(svalue, out services)) {
683                         return services;
684                     }
685                     else {
686                         if (svalue.IndexOf(',') != -1) {
687                             int convertedValue = 0;
688                             string[] values = svalue.Split(new char[] {','});
689                             foreach(string v in values) {
690                                 convertedValue |= (int)(OleDbServiceValues)Enum.Parse(typeof(OleDbServiceValues), v, true);
691                             }
692                             return (int)convertedValue;;
693                         }
694                         else {
695                             return (int)(OleDbServiceValues)Enum.Parse(typeof(OleDbServiceValues), svalue, true);
696                         }
697                     }
698                 }
699                 return base.ConvertFrom(context, culture, value);
700             }
701
702             public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
703                 // Only know how to convert to the NetworkLibrary enumeration
704                 return ((typeof(string) == destinationType) || base.CanConvertTo(context, destinationType));
705             }
706
707             public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
708                 if ((typeof(string) == destinationType) && (null != value) && (typeof(Int32) == value.GetType())) {
709                     return Enum.Format(typeof(OleDbServiceValues), ((OleDbServiceValues)(int)value), "G");
710                 }
711                 return base.ConvertTo(context, culture, value, destinationType);
712             }
713
714             public override bool GetStandardValuesSupported(ITypeDescriptorContext context) {
715                 return true;
716             }
717
718             public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) {
719                 return false;
720             }
721
722             public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) {
723                 StandardValuesCollection standardValues = _standardValues;
724                 if (null == standardValues) {
725                     Array objValues = Enum.GetValues(typeof(OleDbServiceValues));
726                     Array.Sort(objValues, 0, objValues.Length);
727                     standardValues = new StandardValuesCollection(objValues);
728                     _standardValues = standardValues;
729                 }
730                 return standardValues;
731             }
732
733             public override bool IsValid(ITypeDescriptorContext context, object value) {
734                 return true;
735                 //return Enum.IsDefined(type, value);
736             }
737         }
738
739         sealed internal class OleDbConnectionStringBuilderConverter : ExpandableObjectConverter {
740
741             // converter classes should have public ctor
742             public OleDbConnectionStringBuilderConverter() {
743             }
744
745             override public bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
746                 if (typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor) == destinationType) {
747                     return true;
748                 }
749                 return base.CanConvertTo(context, destinationType);
750             }
751
752             override public object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
753                 if (destinationType == null) {
754                     throw ADP.ArgumentNull("destinationType");
755                 }
756                 if (typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor) == destinationType) {
757                     OleDbConnectionStringBuilder obj = (value as OleDbConnectionStringBuilder);
758                     if (null != obj) {
759                         return ConvertToInstanceDescriptor(obj);
760                     }
761                 }
762                 return base.ConvertTo(context, culture, value, destinationType);
763             }
764
765             private System.ComponentModel.Design.Serialization.InstanceDescriptor ConvertToInstanceDescriptor(OleDbConnectionStringBuilder options) {
766                 Type[] ctorParams = new Type[] { typeof(string) };
767                 object[] ctorValues = new object[] { options.ConnectionString };
768                 System.Reflection.ConstructorInfo ctor = typeof(OleDbConnectionStringBuilder).GetConstructor(ctorParams);
769                 return new System.ComponentModel.Design.Serialization.InstanceDescriptor(ctor, ctorValues);
770             }
771         }
772     }
773 }