动态库使用Demo程序演示
#include
#include
#include "sqlDataBase.h"
int main()
{
if (SQLInit() == S_OK)
{
std::cout << "数据库连接成功" << std::endl;
}
return false;
}
【SqlDataBase】库头文件(.h)
/*
* "Copyright (c) 2021 by Sinux,Inc,liumeng"
*/
#ifndef __SQLDATABASE_H__
#define __SQLDATABASE_H__
#ifdef SQLDATABASE_EXPORTS
#define SQLDATABASEOPT_API __declspec(dllexport)
#else
#define SQLDATABASEOPT_API __declspec(dllimport)
#pragma comment(lib,"SqlDataBase.lib")
#endif
#include
/**
* SQL connect stringt
* Provider=SQLOLEDB;Data Source=127.0.0.1,1433;Initial Catalog=sa;User Id=sa;Password=1
* MS Access connect string
* Provider=Microsoft.Jet.OLEDB.4.0;Data Source=../../../data/db/Demo.mdb
*/
int SQLDATABASEOPT_API SQLInit(
const std::string& strDataSource = "Provider=SQLOLEDB;Data Source=127.0.0.1;Initial Catalog=sa;User Id=sa;Password=123456",
const std::string& strName = "",
const std::string& strPwd = ""
);
void SQLDATABASEOPT_API SQLDestroy();
/*
* 查询数据
* strSQL : SQL 语句
* strResult: 结果 xml形式
* 返回值 > 0执行成功,返回记录的条数,否则失败
*/
int SQLDATABASEOPT_API SQLQuery(const std::string& strSQL, std::string& strResult);
/*
* 删除数据
*/
bool SQLDATABASEOPT_API SQLDelete(const std::string& value);
/*
* 添加数据,需要输入id
*/
bool SQLDATABASEOPT_API SQLInsert(const const std::string& str);
/*
* 更新数据
*/
bool SQLDATABASEOPT_API SQLUpdate(const std::string& str);
#endif
【SqlDataBase】库源代码(.cpp)
#define WIN32_LEAN_AND_MEAN
#include
#include
#include
#import "C:/Program Files/Common Files/System/ado/msado15.dll" rename("EOF","EndOfFile")
#include "SqlDataBase.h"
#include
#include
using std::string;
using namespace ADODB;
/************************************************************************/
/* 互斥体对象声明 */
/************************************************************************/
class Mutex
{
public:
Mutex()
{
/**
* 初始化临界区对象
* 返回值>无
*/
::InitializeCriticalSection(&m_cs);
}
~Mutex()
{
/**
* 释放临界区对象
* 返回值>无
*/
::DeleteCriticalSection(&m_cs);
}
void Lock()
{
/**
* 进入临界截面
* 返回值>无
*/
::EnterCriticalSection(&m_cs);
}
void UnLock()
{
/**
* 离开临界截面
* 返回值>无
*/
::LeaveCriticalSection(&m_cs);
}
protected:
CRITICAL_SECTION m_cs;
};
/************************************************************************/
/* 互斥锁对象声明 */
/************************************************************************/
class Lock
{
public:
Lock(Mutex* pM) :m_Mutex(*pM)
{
m_Mutex.Lock();
}
Lock(Mutex& m) :m_Mutex(m)
{
m_Mutex.Lock();
}
~Lock()
{
m_Mutex.UnLock();
}
public:
Mutex& m_Mutex;
};
_ConnectionPtr g_pConnection = NULL;
Mutex g_Mutex;
/************************************************************************/
/* 初始化数据库连接 */
/************************************************************************/
int SQLDATABASEOPT_API SQLInit(
const std::string& strDataSource,
const std::string& strUserName,
const std::string& strPwd
)
{
//创建自动互斥锁将该函数加锁,保证全局对象的安全性
Lock lk(g_Mutex);
//以单线程方式创建COM对象
//Microsoft 组件对象模型 (COM) 是一个独立于平台的分布式面向对象的系统,用于创建可交互的二进制软件组件。
//COM 是 Microsoft 的 OLE (复合文档) 、ActiveX (Internet 组件) 等的基础技术。
if (::CoInitialize(NULL)!= S_OK)
{
OutputDebugString(_T("CoInitialize failed!\n"));
}
//创建ADO接口
//ADO是微软提供的COM,用于访问数据库。
g_pConnection.CreateInstance(__uuidof(Connection));
try
{
HRESULT hr = g_pConnection->Open((_bstr_t)strDataSource.c_str(), strUserName.c_str(), strPwd.c_str(), adModeUnknown);
return S_OK;
}
catch (_com_error e)
{
OutputDebugString(e.Description());
OutputDebugString(_T("\n"));
return e.Error();
}
catch (...)
{
return -1;
}
return false;
}
/************************************************************************/
/* 释放连接 */
/************************************************************************/
void SQLDATABASEOPT_API SQLDestroy()
{
g_pConnection = NULL;
}
/************************************************************************/
/* 查询数据 */
/************************************************************************/
int SQLDATABASEOPT_API SQLQuery(const string& strSQL, string& strRet)
{
Lock lk(g_Mutex);
/**
* 清空数据
*/
strRet = "";
_RecordsetPtr pRecordSet;
pRecordSet.CreateInstance(__uuidof(Recordset));
try
{
//打开数据库
pRecordSet->Open
(
strSQL.c_str(),
g_pConnection.GetInterfacePtr(),
adOpenDynamic,
adLockOptimistic,
adCmdText
);
if (!pRecordSet->BOF)
{
pRecordSet->MoveFirst();
OutputDebugString(_T("数据库打开数据集合成功\n"));
}
else
{
OutputDebugString(_T("暂无数据\n"));
return 0;
}
std::stringstream ss;
ss << "\n" ;
int iRecordCnt = 0;
while (!pRecordSet->EndOfFile)
{
ss << "\t;
++iRecordCnt;
//取得表中字段数目
long lCnt = pRecordSet->Fields->Count;
for (int i = 0; i < lCnt; ++i)
{
std::string strResult;
//第几个字段
FieldPtr fields = pRecordSet->Fields->Item[long(i)];
//字段名称
string fieldName = (LPCSTR)fields->GetName();
//字段值
_variant_t var = pRecordSet->GetCollect(fieldName.c_str());
if (var.vt != VT_NULL)
{
strResult = (LPCSTR)_bstr_t(var);
std::string::iterator itr = strResult.begin();
for (
; itr != strResult.end();
)
{
std::string strData;;
if (*itr == '\"')
{
size_t nPos = itr - strResult.begin();
strData = """;
strResult.replace(itr, itr + 1, strData.c_str(), strData.size());
itr = strResult.begin() + (nPos)+strData.size();
}
else if (*itr == '\'')
{
size_t nPos = itr - strResult.begin();
strData = "'";
strResult.replace(itr, itr + 1, strData.c_str(), strData.size());
itr = strResult.begin() + (nPos)+strData.size();
}
else if (*itr == '>')
{
size_t nPos = itr - strResult.begin();
strData = ">";
strResult.replace(itr, itr + 1, strData.c_str(), strData.size());
itr = strResult.begin() + (nPos)+strData.size();
}
else if (*itr == '<')
{
size_t nPos = itr - strResult.begin();
strData = "<";
strResult.replace(itr, itr + 1, strData.c_str(), strData.size());
itr = strResult.begin() + (nPos)+strData.size();
}
else if (*itr == '&')
{
size_t nPos = itr - strResult.begin();
strData = "&";
strResult.replace(itr, itr + 1, strData.c_str(), strData.size());
itr = strResult.begin() + (nPos)+strData.size();
}
else
{
++itr;
}
}
}
ss << fieldName << " = \"" << strResult << "\" ";
}
ss << "/>\n";
pRecordSet->MoveNext();
}
ss << "";
strRet = ss.str();
pRecordSet->Close();
return iRecordCnt;
}
catch (_com_error e)
{
strRet = "";
OutputDebugString(e.ErrorMessage());
OutputDebugString(_T("\n"));
return e.Error();
}
catch (...)
{
return -1;
}
}
/************************************************************************/
/* 删除数据 */
/************************************************************************/
bool SQLDATABASEOPT_API SQLDelete(const std::string& value)
{
try
{
Lock lk(g_Mutex);
//_CommandPtr是一种函数,功能是提交的sql查询字符串指针。
_CommandPtr pCommand = NULL;
//初始化Com对象
pCommand.CreateInstance(__uuidof(Command));
//连接数据库
pCommand->ActiveConnection = g_pConnection;
//命令文本
pCommand->CommandText = value.c_str();
//执行
pCommand->Execute(NULL, NULL, adCmdText);
return true;
}
catch (_com_error e)
{
OutputDebugString(e.ErrorMessage());
return false;
}
}
/************************************************************************/
/* 添加数据,添加的时候需要手动输入id值 */
/************************************************************************/
bool SQLDATABASEOPT_API SQLInsert(const std::string& str)
{
try
{
Lock lk(g_Mutex);
_CommandPtr pCommand = NULL;
//初始化Com对象
pCommand.CreateInstance(__uuidof(Command));
//连接数据库
pCommand->ActiveConnection = g_pConnection;
//命令文本
pCommand->CommandText = str.c_str();
//执行
pCommand->Execute(NULL, NULL, adCmdText);
return true;
}
catch (_com_error e)
{
OutputDebugString(e.ErrorMessage());
return false;
}
}
/************************************************************************/
/* 更新数据库 */
/************************************************************************/
bool SQLDATABASEOPT_API SQLUpdate(const std::string& str)
{
try
{
Lock lk(g_Mutex);
_CommandPtr pCommand = NULL;
//初始化Com对象
pCommand.CreateInstance(__uuidof(Command));
//连接数据库
pCommand->ActiveConnection = g_pConnection;
//命令文本
pCommand->CommandText = str.c_str();
//执行
pCommand->Execute(NULL, NULL, adCmdText);
return true;
}
catch (_com_error e)
{
OutputDebugString(e.ErrorMessage());
return false;
}
}
动态库使用方法
打开 Visual Studio 这里用2019来演示,选择创建新项目
连着选择动态链接库DLL,各个版本的VS叫法可能不一样,总之是DLL就对了
项目名称取名为SqlDataBase,如果不是这个名字的话后面需要在源代码中修改,总之在动态库CPP中要写清楚.lib的名称,这个名称通常和项目名称相同。当然你也可以在项目属性中修改生成库的名称。
#pragma comment(lib,"SqlDataBase.lib")
创建好项目之后在解决方案视图当中Visual Studio会为我们自动创建两个.h和.cpp这里还是以Visual Studio 2019为例。当然我们不需要这些文件,所以我在这里将它删除掉
将它们全部删除掉,得到一个干净的工程。
这个时候我们创建我们的.cpp和.h,怎么创建都行了,文件名叫什么也不重要,但是为了遵循C++的代码规范,我这里还是将文件名称创建为SqlDataBase.h,SqlDataBase.cpp
接下来直接将我们的代码对应.h以及.cpp复制进去,然后在解决方案资源管理视图中右键我们的项目或则解决方案,都行。这个时候如果不出意外的话应该就要出意外了。
错误提示我们是否忘记了向源中添加#include “pch.h”
这是我们使用了预编译头的但是却把源文件删除了导致的,我们只需要在工程属性中将预编译头去掉,不使用它即可。
然后再进行编译这个时候如果不出意外的话也会出意外
我们定义的库导出函数是不运行进行导入定义的,这是我们在定义/使用 库函数的规范,如果想要详细了解的话可以参考windows动态库的有关知识。总之,我们需要对工程进行预处理器定义,告诉编译器,我们的定义的函数用于导出,也就是
#ifdef SQLDATABASE_EXPORTS
#define SQLDATABASEOPT_API __declspec(dllexport)
同样选择我们的项目右键,然后点击属性,找到C++栏,预处理器,然后将预处理定义加上SQLDATABASE_EXPORTS,我们在代码中定义的#define
添加进去点击确认
再次对工程进行生成,这个时候如果不出意外的话就不会出现意外了。
这个时候我们可以在Visual Studio下方输出视图中查看我们的库生成在了那里,并且找到他。做完了这些步骤之后,我们就得到了一个对SQLServer数据库 *** 作的动态库了。我们可以进行连接,查询,删除,修改等 *** 作。
这个时候让我们新建一个空项目来测试动态库是否可用,哦,在这之前,你需要知道,如果要使用一个动态库,需要.dll,.lib以及关于他导出函数声明的头文件。当然,如果我们生成成功了,.dll,.lib都会在生成目录中找到,头文件就直接使用SqlDataBase.h就想,因为在SqlDataBase.h中,我们也定义了有关于导入的 *** 作
#define SQLDATABASEOPT_API __declspec(dllimport)
#pragma comment(lib,"SqlDataBase.lib")
好了,我们现在新创建一个名为sqlDemo的项目并把SqlDataBase.h,SqlDataBase.lib,以及SqlDataBase.dll包含在我们的项目中
我这里在工程根目录下面创建了一个名为include的文件夹,并将SqlDataBase.h放到了其中,在sqlDemo工程中,我们添加附加包含目录,就可以使用我们的SqlDataBase.h头文件了。
同样我们也设置一下lib的路径。我也是在工程根目录下面创建了一个名为lib的文件夹,然后将我们生成出来的.lib文件放到了其中
还剩下最后一步,也是最关键的一步,我们需要在sqlDemo工程属性中告诉编译器,我们需要依赖一个名为SqlDataBase的库,这样呢,编译器就会在程序编译期间将我们准备好的SqlDataBase库与我们的Demo程序连接在一起了。确保我们在首次调用库函数的时候已经加载好了库。
因为我们在连接器常规属性中,附加库目录中配置了我们的lib目录,所以呢,编译器也会找到我们的lib文件,如果你没有配置该目录的话,编译器就不会找到,当然如果你愿意的话,也可以直接放在程序根目录下面,且不用配置附加库目录,只不过这样看起来有一点乱,在大型工程中,对于文件的管理要求都必须清晰明了,如果我们有非常多个.lib文件的话,把他们统一放在一起是一个不错的选择。
好了,接下来就是最后一步了,将我们的DLL文件放在工程的根目录下面。
这个时候再运行我们的Demo程序,看看我们的动态库是否能正常运行起来
关于数据库的连接您可以访问SQLInit()的构造函数,如果您不清楚数据库的搭建,嗯,我想您可以查阅一些书籍,或则是上网求助,如果可以,您也可以询问一下身边经验丰富的同事。总之这里不涉及数据库搭建的 *** 作。
PS:严格来讲,您不需对sqlDemo程序进行附加依赖库的 *** 作,因为如果您的sqlDemo程序已经成功包含了sqlDataBase.h头文件,在程序编译的过程中呢就会连接lib库了
#define SQLDATABASEOPT_API __declspec(dllimport)
#pragma comment(lib,"SqlDataBase.lib")
我们在头文件中说明了库的导入。
所以,在进入main函数之前,或则说在编译Demo.cpp中就已经导入了动态库,您无需担心在使用库函数之前是否已经加载进了库。但在这所有所有之前,您至少需要让编译器找到您的lib库。
祝您好运~~~~
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)