// // (C) Copyright 2003-2009 by Autodesk, Inc. // // Permission to use, copy, modify, and distribute this software in // object code form for any purpose and without fee is hereby granted, // provided that the above copyright notice appears in all copies and // that both that copyright notice and the limited warranty and // restricted rights notice below appear in all supporting // documentation. // // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE // UNINTERRUPTED OR ERROR FREE. // // Use, duplication, or disclosure by the U.S. Government is subject to // restrictions set forth in FAR 52.227-19 (Commercial Computer // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. // using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Data.Odbc; using System.Windows.Forms; using System.Resources; using System.Collections; using System.Runtime.InteropServices; using System.Reflection; using System.Data; namespace Revit.SDK.Samples.RDBLink.CS { /// /// Provides method to pop up ODBC data source selection dialog. /// public class SQLDriver { #region Fields //driver completion modes const ushort SQL_DRIVER_NOPROMPT = 0; const ushort SQL_DRIVER_COMPLETE = 1; const ushort SQL_DRIVER_PROMPT = 2; const ushort SQL_DRIVER_COMPLETE_REQUIRED = 3; const short SQL_NTS = -3; /* FreeStmt() options */ const short SQL_CLOSE = 0; const short SQL_DROP = 1; const short SQL_UNBIND = 2; const short SQL_RESET_PARAMS = 3; //return values const short SQL_SUCCESS = 0; const short SQL_SUCCESS_WITH_INFO = 1; const short SQL_STILL_EXECUTING = 2; const short SQL_NEED_DATA = 99; const short SQL_NO_DATA = 100; const short SQL_ERROR = (-1); const short SQL_INVALID_HANDLE = (-2); //handles static IntPtr environmentHandle = IntPtr.Zero; static IntPtr connectionHandle = IntPtr.Zero; static IntPtr stmtHandle = IntPtr.Zero; //allocated flag static bool isAllocated; #endregion #region Methods #region Win32API /// /// Get current window handle /// /// Current window handle [DllImport("user32.dll")] static extern IntPtr GetActiveWindow(); /// /// SQLDriverConnect is an alternative to SQLConnect. It supports data sources that /// require more connection information than the three arguments in SQLConnect, /// dialog boxes to prompt the user for all connection information, /// and data sources that are not defined in the system information. /// /// Connection handle. /// Window handle. /// A full connection string, a partial connection string, /// or an empty string. /// Length of *InConnectionString, in characters. /// A buffer for the completed connection string. /// Length of the *OutConnectionString buffer. /// A buffer in which to return the total number of characters /// (excluding the null-termination character) /// available to return in *OutConnectionString. /// flag that indicates whether the Driver Manager or /// driver must prompt for more connection information. /// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA, SQL_ERROR, /// or SQL_INVALID_HANDLE. [DllImport("odbc32.dll", CharSet = CharSet.Unicode)] static extern short SQLDriverConnect(IntPtr hdbc, IntPtr hwnd, string szConnStrIn, short cbConnStrIn, StringBuilder szConnStrOut, short cbConnStrOutMax, out short pcbConnStrOut, ushort fDriverCompletion); /// /// Releases a connection handle and frees all memory associated with the handle. /// /// ConnectionHandle /// SQL_SUCCESS, SQL_ERROR, or SQL_INVALID_HANDLE. [DllImport("odbc32.dll", CharSet = CharSet.Unicode)] static extern short SQLFreeConnect(IntPtr ConnectionHandle); /// /// closes the connection associated with a specific connection handle. /// /// ConnectionHandle /// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE [DllImport("odbc32.dll", CharSet = CharSet.Unicode)] static extern short SQLDisconnect(IntPtr ConnectionHandle); /// /// Frees an given ODBC Environment handle /// /// EnvironmentHandle /// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR [DllImport("odbc32.dll", CharSet = CharSet.Unicode)] static extern short SQLFreeEnv(IntPtr EnvironmentHandle); /// /// Allocates memory for an environment handle and initializes the ODBC call level /// interface for use by an application. /// /// EnvironmentHandle /// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR [DllImport("odbc32.dll")] static extern short SQLAllocEnv(out IntPtr EnvironmentHandle); /// /// Allocates memory for a connection handle within the environment. /// /// EnvironmentHandle /// ConnectionHandle [DllImport("odbc32.dll")] static extern short SQLAllocConnect(IntPtr EnvironmentHandle, out IntPtr ConnectionHandle); /// /// Allocates a new statement handle and associates it with the connection /// specified by the connection handle. /// /// Connection handle /// Statement handle /// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR [DllImport("odbc32.dll")] static extern short SQLAllocStmt(IntPtr ConnectionHandle, out IntPtr StmtHandle); /// /// Free (or Reset) a Statement Handle, /// Ends processing on the statement referenced by the statement handle. /// Use this function to: Close a cursor,Reset parameters /// and Unbind columns from variables. /// /// Statement handle. /// Option specifying the manner /// of freeing the statement handle. /// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR [DllImport("odbc32.dll")] static extern short SQLFreeStmt(IntPtr StmtHandle, short Option); /// /// Execute SQL statement directly. /// /// Statement handle /// Statement content /// Statement text length /// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR [DllImport("odbc32.dll", CharSet = CharSet.Unicode)] static extern short SQLExecDirect(IntPtr StatementHandle, string StatementText, int TextLength); /// /// Returns a list of table names and associated information /// stored in the system catalogs of the connected data source. /// /// Statement handle /// Buffer that may contain a pattern-value /// to qualify the result set. Catalog is the first part of a three-part table name. /// This must be a NULL pointer or a zero length string. /// Length of CatalogName. This must be set to 0. /// Buffer that may contain a pattern-value to qualify /// the result set by schema name. /// Length of SchemaName. /// Buffer that may contain a pattern-value /// to qualify the result set by table name. /// Length of TableName. /// Buffer that may contain a value list to qualify /// the result set by table type. /// Size of Table type. /// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR [DllImport("odbc32.dll", CharSet = CharSet.Unicode)] static extern short SQLTables(IntPtr StatementHandle, string CatalogName, short NameLength1, string SchemaName, short NameLength2, string TableName, short NameLength3, string TableType, short NameLength4); /// /// Returns a list of columns in the specified tables. /// /// Statement handle. /// Catalog name /// Catalog name length /// Schema name /// Schema name length /// Table name /// Table name length /// Column name /// Column name length /// [DllImport("odbc32.dll", CharSet = CharSet.Unicode)] static extern short SQLColumns(IntPtr StatementHandle, string CatalogName, short NameLength1, string SchemaName, short NameLength2, string TableName, short NameLength3, string ColumnName, short NameLength4); /// /// Advances the cursor to the next row of the result set, and retrieves any bound columns. /// /// Statement handle. /// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, /// SQL_NO_DATA_FOUND, or SQL_ERROR. [DllImport("odbc32.dll")] static extern short SQLFetch(IntPtr StatementHandle); /// /// Closes the open cursor on a statement handle. /// /// Statement handle. /// SQL_SUCCESS, SQL_INVALID_HANDLE, or SQL_ERROR [DllImport("odbc32.dll")] static extern short SQLCloseCursor(IntPtr StatementHandle); /// /// Returns general information (including supported data conversions) /// about the DBMS to which the application is connected. /// /// Database connection handle /// The type of information desired. The argument /// must be one of the values in the first column of the tables in Data /// Types and Data Conversion. /// Pointer to buffer where this function stores /// the necessary information. /// Maximum size of the buffer pointed to by /// rgbInfoValue. /// Pointer to location where this function returns /// the total number of bytes available to return the desired information. /// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO , SQL_INVALID_HANDLE, /// or SQL_ERROR [DllImport("odbc32.dll", EntryPoint = "SQLGetInfo")] static extern short SQLGetInfo(IntPtr sqlHdbc, short fInfoType, [Out] StringBuilder rgbInfoValue, short cbInfoValueMax, out short pcbInfoValue); #endregion /// /// Verify value is SQL_SUCCESS or SQL_SUCCESS_WITH_INFO /// /// value to verify /// true if value is SQL_SUCCESS or SQL_SUCCESS_WITH_INFO static bool IsOK(int value) { return value == SQL_SUCCESS || value == SQL_SUCCESS_WITH_INFO; } /// /// Initializes environment, allocate memory for environment and connection /// /// true if initialize successfully static bool Initialize() { if (!isAllocated) { if (!IsOK(SQLAllocEnv(out environmentHandle))) { return false; } if (!IsOK(SQLAllocConnect(environmentHandle, out connectionHandle))) { return false; } isAllocated = true; } return true; } /// /// Connect a database and return the connection string /// /// A full connection string, a partial connection string, /// or an empty string. /// flag that indicates whether the Driver Manager or /// driver must prompt for more connection information. /// The completed connection string /// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA, SQL_ERROR, /// or SQL_INVALID_HANDLE. static int Connect(string in_connect, ushort driverCompletion, ref string retConnStr) { retConnStr = string.Empty; const short MAX_CONNECT_LEN = 1024; StringBuilder out_connect = new StringBuilder(MAX_CONNECT_LEN); short len = 0; int retval = SQL_ERROR; // initializes environment if (!Initialize()) return retval; // pop up dialog for user to select data source retval = SQLDriverConnect(connectionHandle, GetActiveWindow(), in_connect, (short)in_connect.Length, out_connect, MAX_CONNECT_LEN, out len, driverCompletion); retConnStr = out_connect.ToString(); if (IsOK(SQLAllocStmt(connectionHandle, out stmtHandle))) { } return retval; } /// /// Execute SQL statement. /// /// SQL statement. public bool ExecuteSQL(string sqlStmt) { short status = SQLExecDirect(stmtHandle, sqlStmt, sqlStmt.Length); return IsOK(status); } /// /// Return whether the table exist in database. /// /// Table name. /// True of False. public bool TableExist(string tableName) { short status = SQLTables(stmtHandle, null, 0, null, 0, tableName, SQL_NTS, null, 0); if (!IsOK(status)) { SQLCloseCursor(stmtHandle); return false; } else { status = SQLFetch(stmtHandle); if (IsOK(status)) { SQLCloseCursor(stmtHandle); return true; } else { SQLCloseCursor(stmtHandle); return false; } } } /// /// Judge whether the column exist in data table or not. /// /// Data table name /// Column name /// True or False public bool ColumnExist(string tableName, string columnName) { short status = SQLColumns(stmtHandle, null, 0, null, 0, tableName, SQL_NTS, columnName, SQL_NTS); if (!IsOK(status)) { SQLCloseCursor(stmtHandle); return false; } else { status = SQLFetch(stmtHandle); if (IsOK(status)) { SQLCloseCursor(stmtHandle); return true; } else { SQLCloseCursor(stmtHandle); return false; } } } /// /// Close connection and free memory /// public void Terminate() { if (stmtHandle.ToInt32() != 0) { SQLFreeStmt(stmtHandle, SQL_CLOSE); stmtHandle = IntPtr.Zero; } if (connectionHandle.ToInt32() != 0) { SQLDisconnect(connectionHandle); } if (connectionHandle.ToInt32() != 0) { SQLFreeConnect(connectionHandle); connectionHandle = IntPtr.Zero; } if (environmentHandle.ToInt32() != 0) { SQLFreeEnv(environmentHandle); environmentHandle = IntPtr.Zero; } isAllocated = false; } /// /// Pop up data source dialog to select a data source and return connection string. /// /// Connection string of selected data source /// Selected database type public DatabaseType SelectDatabase(ref string connectStr) { int state = SQLDriver.Connect("", SQLDriver.SQL_DRIVER_PROMPT, ref connectStr); if (state != SQLDriver.SQL_SUCCESS && state != SQLDriver.SQL_SUCCESS_WITH_INFO) { return DatabaseType.Invalid; } short MaxLength = 1000; StringBuilder value = new StringBuilder(MaxLength); short SQL_DBMS_NAME = 17; short retv = 0; SQLGetInfo(connectionHandle, SQL_DBMS_NAME, value, MaxLength, out retv); switch (value.ToString()) { case "Microsoft SQL Server": return DatabaseType.SQLServer; case "ACCESS": return DatabaseType.MSAccess; default: return DatabaseType.Invalid; } } #endregion } /// /// Indicates supported databases /// public enum DatabaseType { /// /// Default /// Invalid, /// /// SQLServer is supported /// SQLServer, /// /// Microsoft Access is supported /// MSAccess } }