VC++ *** 作SQLserver动态库【含源码】,及动态库使用教程。

VC++ *** 作SQLserver动态库【含源码】,及动态库使用教程。,第1张

VC++ *** 作SQLserver动态库【含源码】

动态库使用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库。
祝您好运~~~~

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/740967.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-28
下一篇 2022-04-28

发表评论

登录后才能评论

评论列表(0条)

保存