文章作者:板儿砖/heart
信息来源:进阶网(
www.secrity.cn)
原始连接:
http://www.secrity.cn/attackarc.asp?id=22
在网上搜了很长时间都没有结果,于是小弟细细研读MSDN得出此文,首先我们看一下实现此功能的核心函数
:SQLTables关于这个函数MSDN是这样描述的:
SQLTables returns the list of table, catalog, or schema names, and table types, stored in a
specific data source. The driver returns the information as a result set.
大概译为:SQLTables函数返回库中所有表名列表,目录,图式或名称,表类型,存放在一个特定的数据源中.
返回信息作为一个结果集进行访问.
函数的原型为:SQLRETURN SQLTables(
SQLHSTMTStatementHandle,
SQLCHAR *CatalogName,
SQLSMALLINTNameLength1,
SQLCHAR *SchemaName,
SQLSMALLINTNameLength2,
SQLCHAR *TableName,
SQLSMALLINTNameLength3,
SQLCHAR *TableType,
SQLSMALLINTNameLength4);
由此我们可以知道,只要对库的连接进行了初始化设置如,申请环境变量并设置,申请连接变量并设置,连接
库等.便可申请一个语句句柄来得到库中所有表名列表.
示例程序如下:
#include <windows.h>
#include <wchar.h>
#include <sqlext.h>//SQL常用函数及变量定义
typedef struct _ODBC_RS {
SQLHSTMT hStmt;
SQLSMALLINT iCols;
HGLOBAL lpstr[100];
int iRows;
int temp;
}ODBC_RS ;
BOOL Rs_Open(ODBC_RS * _strRs)
{
SQLSMALLINT hret;
int iCols;
int iColLength,iPointLength,bNull,iDataType,iStrlength;
char szColName[256];//列名返回值缓冲区。
SQLNumResultCols((* _strRs).hStmt,&((* _strRs).iCols));
if ((* _strRs).iCols<=0)
{
MessageBox(NULL,"无法得到结果集中的行数","erro!",MB_OK);
return FALSE;
}
if((* _strRs).iCols>100) //大于100列则取前100列
{
(* _strRs).iCols=100;
}
for(iCols=1;iCols<=(* _strRs).iCols;iCols++)
{
hret=SQLDescribeCol((* _strRs).hStmt,iCols,\
szColName,sizeof(szColName),\
&iColLength,&iDataType,\
&iColLength,&iPointLength,&bNull);
if (hret !=SQL_SUCCESS && hret !=SQL_SUCCESS_WITH_INFO)
{
MessageBox(NULL,TEXT("取得列属性时出错!"),TEXT("erro!"),MB_OK);
return FALSE;
}
iColLength=iColLength*2+1;
(* _strRs).lpstr[iCols]=GlobalAlloc(GPTR,iColLength);
if((* _strRs).lpstr[iCols]==NULL)
{
MessageBox(NULL,"分配内存出错","erro!",MB_OK);
return FALSE;
}
hret=SQLBindCol((* _strRs).hStmt,iCols,\
SQL_C_CHAR,(* _strRs).lpstr[iCols],\
iColLength,&iStrlength);
if (hret !=SQL_SUCCESS && hret !=SQL_SUCCESS_WITH_INFO)
{
MessageBox(NULL,TEXT("取得列属性时出错!"),TEXT("erro!"),MB_OK);
return FALSE;
}
}
return TRUE;
}
int main(int argc,char * argv[])
{
char a;
HINSTANCE hInstance=GetModuleHandle(NULL);
SQLSMALLINT hret;
char sqlstr[1024];
HINSTANCE hin; //函数返回值
SQLHENV hEnv; //环境句柄
SQLHDBC hDbc; //连接句柄
SQLHSTMT hStmt;
int constr1len;
char sqlstr1[1024];
ODBC_RS rslist;
if(argc<2 || (strstr(argv[1],".mdb")==NULL))
{
printf("erro!~");
return 0;
}
wsprintf(sqlstr,"DRIVER=Microsoft Access Driver (*.mdb);DBQ=%s",argv[1]);
hret=SQLAllocHandle(SQL_HANDLE_ENV,NULL,&hEnv);
if (hret !=SQL_SUCCESS && hret !=SQL_SUCCESS_WITH_INFO)
//容错处理
{
MessageBox(NULL,TEXT("分配环境句柄进出现错误"),TEXT("erro!"),MB_OK);
return 0;
}
hret=SQLSetEnvAttr(hEnv,SQL_ATTR_ODBC_VERSION,SQL_OV_ODBC3,0);
//设置环境句柄
if (hret !=SQL_SUCCESS && hret !=SQL_SUCCESS_WITH_INFO)
{
MessageBox(NULL,TEXT("设置环境句柄时出现错误"),TEXT("erro!"),MB_OK);
return 0;
}
hret=SQLAllocHandle(SQL_HANDLE_DBC,hEnv,&hDbc);
if (hret !=SQL_SUCCESS && hret !=SQL_SUCCESS_WITH_INFO)
{
MessageBox(NULL,TEXT("分配连接句柄时出现错误"),TEXT("erro!"),MB_OK);
return 0;
}
hret=SQLDriverConnect(hDbc,NULL,sqlstr,sizeof(sqlstr),\
sqlstr1,sizeof(sqlstr1),&constr1len,\
SQL_DRIVER_COMPLETE);
printf("the complete connect string:%s",sqlstr1);
hret=SQLAllocHandle(SQL_HANDLE_STMT,hDbc,&hStmt);
if (hret !=SQL_SUCCESS && hret !
=SQL_SUCCESS_WITH_INFO && hret!=SQL_NO_DATA)
{
MessageBox(NULL,TEXT("分配语
句句柄失败"),TEXT("erro!"),MB_OK);
return 0;
}
hret=SQLSetStmtAttr
(hStmt,SQL_ATTR_CURSOR_TYPE,SQL_CURSOR_STATIC,0);
if (hret !=SQL_SUCCESS && hret !
=SQL_SUCCESS_WITH_INFO)
{
MessageBox(NULL,TEXT("设置语
句时出现错误"),\
TEXT
("erro!"),MB_OK);
return 0;
}
hret=SQLTables
(hStmt,NULL,0,NULL,0,NULL,0,NULL,0);
rslist.hStmt=hStmt;
Rs_Open(&rslist);
while(TRUE)
{
hret=SQLFetchScroll
(rslist.hStmt,SQL_FETCH_NEXT,0);
if
(hret==SQL_NO_DATA)
{
RtlZeroMemory(rslist.lpstr[3],\
sizeof(rslist.lpstr[3]));
//清空缓冲区防止对下次操作的影响
return 0;
}
printf("%10s%10s%
10s%10s\n",rslist.lpstr[1],rslist.lpstr[2],rslist.lpstr[3],rslist.lpstr[4]);
RtlZeroMemory
(rslist.lpstr[3],\
sizeof(rslist.lpstr[3]));
//清空缓冲区防止对下次操作的影响
rslist.iRows++;
}
scanf("%c",&a);
SQLDisconnect(hDbc);
SQLFreeHandle(SQL_HANDLE_DBC,hDbc);
SQLFreeHandle(SQL_HANDLE_ENV,hEnv);
return 0;
}
程序在windowsXPsp1+VC++6.0下调试通过,程序使用方法为:程序名 MDB文件完整路径(如在本目录可以不
是完整路径).
本人水平有限错误之处请大侠指正,QQ:283965069 欢迎交流