Skip to content

Instantly share code, notes, and snippets.

@jmelosegui
Created May 15, 2017 17:40
Show Gist options
  • Save jmelosegui/1cd64850094a6881622205a46edc2e9b to your computer and use it in GitHub Desktop.
Save jmelosegui/1cd64850094a6881622205a46edc2e9b to your computer and use it in GitHub Desktop.
P/Invoke Odbccp32
public class Odbccp32
{
/// <summary>
/// From sql.h
/// </summary>
private const int SQL_MAX_MESSAGE_LENGTH = 512;
[DllImport(nameof(Odbccp32), CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SQLGetInstalledDrivers(char[] lpszBuf, ushort cbufMax, out ushort pcbBufOut);
[DllImport(nameof(Odbccp32))]
public static extern SqlReturnCode SQLInstallerError(int iError, out SqlInstallerErrorCode pfErrorCode, StringBuilder lpszErrorMsg, int cbErrorMsgMax, out int pcbErrorMsg);
public static string[] GetOdbcDriverNames()
{
string[] odbcDriverNames = null;
char[] driverNamesBuffer = new char[ushort.MaxValue];
ushort size;
bool succeeded = SQLGetInstalledDrivers(driverNamesBuffer, ushort.MaxValue, out size);
if (!succeeded)
{
string message = GetErrorMessage();
throw new ApplicationException($"Error within a PIvoke call. {message}");
}
char[] driverNames = new char[size - 1];
Array.Copy(driverNamesBuffer, driverNames, size - 1);
odbcDriverNames = (new string(driverNames)).Split('\0');
return odbcDriverNames;
}
public static bool IsSqlServer2016DriverInstalled()
{
return true; //GetOdbcDriverNames().Any(d => d.Equals("ODBC Driver 13 for SQL Server", StringComparison.OrdinalIgnoreCase));
}
private static string GetErrorMessage()
{
StringBuilder result = new StringBuilder();
SqlInstallerErrorCode pfErrorCode;
int bufferSizeNeeded;
int errorRecord = 1;
SqlReturnCode returnCode = SQLInstallerError(errorRecord, out pfErrorCode, result, SQL_MAX_MESSAGE_LENGTH, out bufferSizeNeeded);
if (returnCode == SqlReturnCode.SQL_SUCCESS_WITH_INFO)
{
while (bufferSizeNeeded >= SQL_MAX_MESSAGE_LENGTH)
{
StringBuilder partialMessage = new StringBuilder();
returnCode = SQLInstallerError(++errorRecord, out pfErrorCode, partialMessage, SQL_MAX_MESSAGE_LENGTH, out bufferSizeNeeded);
if (returnCode != SqlReturnCode.SQL_NO_DATA)
{
result.Append(partialMessage);
}
}
}
if (returnCode == SqlReturnCode.SQL_ERROR)
{
result.Append("SQLInstallerError cannot access error values");
}
return result.ToString();
}
}
/// <summary>
/// From sql.h
/// </summary>
public enum SqlReturnCode
{
SQL_ERROR = -1,
SQL_SUCCESS = 0,
SQL_SUCCESS_WITH_INFO = 1,
SQL_NO_DATA = 100
}
/// <summary>
/// From odbcinst.h
/// </summary>
public enum SqlInstallerErrorCode
{
ODBC_ERROR_GENERAL_ERR = 1,
ODBC_ERROR_INVALID_BUFF_LEN = 2,
ODBC_ERROR_COMPONENT_NOT_FOUND = 6,
ODBC_ERROR_OUT_OF_MEM = 21
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment