How to Check for Installed Microsoft.ACE.OLEDB.12.0 Drivers During Installation Process?
In my installation process I am presenting the user with the options for the database of SQL Server, Access (accdb) & Access (mdb). I need to determine if the drivers are installed. Where can I find information on this? I have searched and not found any good information other than to attempt to connect to the database. I plan to include the runtime kit to install if it is not already installed.
The target environment for the client is Windows 10 & 11. With the option to use either SQL Express, SQL Server or Access for the database.
I have found OleDbEnumerator.GetRootEnumerator() as a potential solution. However, from my testing it appears to return values if the ODBC dll is installed, which in my case will work for Access mdb format. The issue with what is returned for SQL Server is just the driver, not if SQL Server is installed. I have tried SqlDataSourceEnumerator.Instance.GetDataSources() which doesn't find the local installation. And from the many posts I've seen it is not very good at finding the local installation. Which led me to try querying the registry for the hive/keys, but I'm concerned the key name can be different with various versions.
I appreciate any guidance to find a good solution. Below is what I have created so far.
internal static class SupportedProviders
{
public static class AccessAccdb
{
public const string SourceName = "Microsoft.ACE.OLEDB.12.0";
internal const string Description = "Microsoft Office 12.0 Access Database Engine OLE DB Provider";
private static bool installed = false;
internal const string DisplayName = "Microsoft Access Database 2007+ (.accdb)";
internal const string Key = "AccessAccdb";
internal const string FileExtension = "accdb";
internal static bool IsInstalled
{
get { QueryOleDbProviders(); return installed; }
set { installed = value; }
}
}
public static class AccessMdb
{
public const string SourceName = "Microsoft.Jet.OLEDB.4.0";
internal const string Description = "Microsoft Jet 4.0 OLE DB Provider";
internal static bool installed = false;
internal const string DisplayName = "Microsoft Access Database 2003 (.mdb)";
internal const string Key = "AccessMdb";
internal const string FileExtension = "mdb";
internal static bool IsInstalled
{
get { QueryOleDbProviders(); return installed; }
set { installed = value; }
}
}
public static class SqlServerExpress
{
public const string SourceName = "SQLOLEDB";
internal const string Description = "Microsoft OLE DB Provider for SQL Server";
internal static bool installed = false;
internal const string DisplayName = "Microsoft Sql Server Express";
internal const string Key = "SqlServerExpress";
internal const string FileExtension = "mdb";
internal static bool IsInstalled
{
get { QueryOleDbProviders(); return installed; }
set { installed = value; }
}
}
private static string[] ToArray()
{
List<string> providers = new List<string>();
try
{
// Get the Type object corresponding to SupportedProviders
Type myType = typeof(SupportedProviders);
// Get an array of nested objects in SupportedProviders and iterate through each
Type[] nestType = myType.GetNestedTypes(BindingFlags.Public);
foreach (Type nType in nestType)
{
//string name = nType.Name;
if (nType.IsClass)
{
// need to get the fields of the class
FieldInfo[] fields = nType.GetFields();
// Loop all fields
foreach (FieldInfo field in fields)
{
if (field.GetValue(nType).GetType() == typeof(string))
{
// Get the value of the field
string s = field.GetValue(typeof(string)).ToString();
// add to the list
providers.Add(field.GetValue(typeof(string)).ToString());
}
}
}
}
}
catch (Exception ex)
{
Logging.AddException(ex,
EventNumbers.DatabaseUnspecified,
"Unable to query OleDb providers.",
EventLogEntryType.Error);
}
return providers.ToArray();
}
internal static bool QueryOleDbProviders()
{
bool result = false;
// Get the supported providers to test
string[] supportedProviders = ToArray();
using (OleDbDataReader dataReader = OleDbEnumerator.GetRootEnumerator())
{
while (dataReader.Read())
{
// Mapping the "SOURCES_NAME" column name for SupportedProviders SourceName field
string providerName = dataReader["SOURCES_NAME"].ToString();
if (supportedProviders.Contains(providerName))
{
// Found one of the supported providers, set the installed flag for each match
for (int i = 0; i < dataReader.FieldCount; i++)
{
if (dataReader.GetName(i) == "SOURCES_NAME") // only process the SOURCES_NAME values
{
string value = dataReader.GetValue(i).ToString();
switch (value)
{
case AccessMdb.SourceName:
AccessMdb.IsInstalled = true;
result = true;
i = dataReader.FieldCount; // end the for loop
break;
case AccessAccdb.SourceName:
AccessAccdb.IsInstalled = true;
result = true;
i = dataReader.FieldCount; // end the for loop
break;
case SqlServerExpress.SourceName:
SqlServerExpress.IsInstalled = true;
result = true;
i = dataReader.FieldCount; // end the for loop
break;
}
}
}
}
}
dataReader.Close();
}
return result;
}
}