Reputation: 1160
I'm trying to get a list of ODBC data sources on a 64 bit Windows 8 system with VS Express 2012 (C#) using SQLDatasources as described in this thread here, I'm referring to the reply by Stephan Keller.
His code compiles fine and runs without any error if the 'prefer 32 bit' option for the target platform is chosen, but runs into a memory access violation if I use 'anycpu' without 'prefer 32 bit' or 'x64' as target platform. I guess (but am not sure) that this is due to the fact that the parameters of the call to SQLDataSources are not correctly aligned in that case, is that correct? (I can see in Process Explorer that the program uses c:\windows\system32\odbc32.dll, which, on a 64 bit Windows System, is 64 bit, so the dll which is used is, to my knowledge, the correct one).
Assuming my guess is correct I searched for but could not find a reference for the mapping from the SQL data types used in ODBC32.dll (like SQLSmallInt, those which are used in the MS documentation Stepan has linked into his answer) to .Net 64 bit data types. Any pointers?
Thanks in advance,
Thomas
Upvotes: 4
Views: 3108
Reputation: 71
I had the same issue and what I did was replace all the ints with longs in the parameters.
Old Calls:
[DllImport("odbc32.dll")]
internal static extern int SQLDataSources(int EnvHandle, int Direction, StringBuilder ServerName, int ServerNameBufferLenIn, ref int ServerNameBufferLenOut, StringBuilder Driver, int DriverBufferLenIn, ref int DriverBufferLenOut);
[DllImport("odbc32.dll")]
internal static extern int SQLAllocEnv(ref int EnvHandle);
New Calls:
[DllImport("odbc32.dll")]
internal static extern int SQLDataSources(long EnvHandle, long Direction, StringBuilder ServerName, long ServerNameBufferLenIn, ref long ServerNameBufferLenOut, StringBuilder Driver, long DriverBufferLenIn, ref long DriverBufferLenOut);
[DllImport("odbc32.dll")]
internal static extern int SQLAllocEnv(ref long EnvHandle);
32-Bit DSNs Won't Appear in the 64-Bit calls.
This is the method I am using (Running Windows 8 x64):
[DllImport("odbc32.dll")]
internal static extern int SQLDataSources(long EnvHandle, long Direction, StringBuilder ServerName, long ServerNameBufferLenIn,
ref long ServerNameBufferLenOut, StringBuilder Driver, long DriverBufferLenIn, ref long DriverBufferLenOut);
[DllImport("odbc32.dll")]
internal static extern int SQLAllocEnv(ref long EnvHandle);
//[DllImport("odbc32.dll")]
//internal static extern int SQLDataSources(int EnvHandle, int Direction, StringBuilder ServerName, int ServerNameBufferLenIn,
// ref int ServerNameBufferLenOut, StringBuilder Driver, int DriverBufferLenIn, ref int DriverBufferLenOut);
//[DllImport("odbc32.dll")]
//internal static extern int SQLAllocEnv(ref int EnvHandle);
public static List<ODBC_System_DSN_Entry> ListODBCsources()
{
List<ODBC_System_DSN_Entry> entries = new List<ODBC_System_DSN_Entry>();
long envHandle = 0;
const long SQL_FETCH_NEXT = 1;
const long SQL_FETCH_FIRST_SYSTEM = 32;
if (SQLAllocEnv(ref envHandle) != -1)
{
long ret;
StringBuilder serverName = new StringBuilder(1024);
StringBuilder driverName = new StringBuilder(1024);
long snLen = 0;
long driverLen = 0;
ret = SQLDataSources(envHandle, SQL_FETCH_FIRST_SYSTEM, serverName, serverName.Capacity, ref snLen,
driverName, driverName.Capacity, ref driverLen);
while (ret == 0)
{
//System.Windows.Forms.MessageBox.Show(serverName + System.Environment.NewLine + driverName);
entries.Add(new ODBC_System_DSN_Entry(serverName.ToString(), driverName.ToString()));
ret = SQLDataSources(envHandle, SQL_FETCH_NEXT, serverName, serverName.Capacity, ref snLen,
driverName, driverName.Capacity, ref driverLen);
}
return entries;
}
return null;
}
public struct ODBC_System_DSN_Entry
{
internal String _server;
internal String _driver;
internal ODBC_System_DSN_Entry(String server, String driver)
{
_server = server;
_driver = driver;
}
public String Server { get { return _server; } }
public String Driver { get { return _driver; } }
}
Upvotes: 6
Reputation: 5992
The first thing I'd do it get the parameter types right. Those name length ptr arguments are SQLSMALLINTs not ints. Also ODBC APIs return SQLRETURN types not int. See SQLDatSources.
Upvotes: 0