动态库使用Demo程序演示
#include【SqlDataBase】库头文件(.h)#include #include "sqlDataBase.h" int main() { if (SQLInit() == S_OK) { std::cout << "数据库连接成功" << std::endl; } return false; }
#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【SqlDataBase】库源代码(.cpp)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(); int SQLDATABASEOPT_API SQLQuery(const std::string& strSQL, std::string& strResult); bool SQLDATABASEOPT_API SQLDelete(const std::string& value); bool SQLDATABASEOPT_API SQLInsert(const const std::string& str); bool SQLDATABASEOPT_API SQLUpdate(const std::string& str); #endif
#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 "; 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; } } 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; } }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 << "
打开 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库。
祝您好运~~~~



