您的位置:首页 > 编程语言 > C语言/C++

BCB(C++ Builder)创建动态库(DLL,接口导出和调用),动态加载DLL

2014-04-03 22:40 555 查看
以前没有封装dll动态库,接触新的工作之后需要用,折腾了一整天,终于搞定了

毕竟是生手,就简单分析注意点和遇到的一些问题及解决方案:

(1)首先准备要生成DLL的工程。

(1.1)我用的是BCB(C++ Builder),File->New->Other...->C++ Builder Projects->Dynamic-Link Library,再根据之后的提示进行,此时工程里有一个File1.cpp,这里就是导出接口的地方了;

(1.2)在Project1.dll上右击->Add New...->Unit,创建一个新的文件,在.cpp和.h文件中编辑你自己的类,一下是我写的一个类,和正常类差不多,就多一个_declspec(dllexport),并且在成员函数前添加__stdcall;我想,既然有了头文件中类的声明,这些类的成员函数在.cpp中该怎么写不必细说吧!头文件之类的我也都省略了!

class _declspec(dllexport) CEmployeeInfo

{

public:

__stdcall CEmployeeInfo(void);

__stdcall ~CEmployeeInfo(void);

HRESULT __stdcall CreateInfo(int nID, const char * pcName, const char * pcPhone);

HRESULT __stdcall UpdateInfo(int nID, const char * pcNewName, const char * pcNewPhone);

HRESULT __stdcall DeleteInfo(int nID);

private:

INFO_T m_stInfo;

};

(1.3)接下来要在File1.cpp中导出供外部访问dll动态库的接口。要把函数接口声明为extern "C"标准,并且接口前面要表明__declspec(dllexport),以后外部就能通过这几个函数访问dll内部的东西了。

CEmployeeInfo *gm_pInfo_Dll = NULL;

extern "C"{

__declspec(dllexport) HRESULT __stdcall CreateEmployeeInfo(int nID,char *pName,char *pPhone);

__declspec(dllexport) HRESULT __stdcall UpdateEmployeeInfo(int nID,char *pName,char *pPhone);

__declspec(dllexport) HRESULT __stdcall DeleteEmployeeInfo(int nID);

}

#pragma argsused

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)

{

return 1;

}

__declspec(dllexport) HRESULT __stdcall CreateEmployeeInfo(int nID,char *pcName,char *pcPhone)

{

return S_OK;

}

__declspec(dllexport) HRESULT __stdcall UpdateEmployeeInfo(int nID,char *pcName,char *pcPhone)

{

return S_OK;

}

__declspec(dllexport) HRESULT __stdcall DeleteEmployeeInfo(int nID)

{

return S_OK;

}

(1.4)做到这里基本搞定,只要编译下,在工程目录Debug下会生成一个Project1.dll文件,就是我们要的动态库!

(2)接下来就要加载调用我们生成的dll动态库了,再创建一个新的工程,File->New->Other...->C++ Builder Projects->VCL Forms Application,双击Form窗体,就能进入代码编辑区。

(2.1)首先在头文件的class TForm1 : public TForm类中定义私有成员变量;

private:// User declarations

HINSTANCE hdll;//用来存放动态库句柄的

(2.2)要在.cpp中声明几个函数指针,放在 TForm1 *Form1之前即可,需要注意的是,接口形式要跟dll中提供的接口一致!!

HRESULT __stdcall (*CreateEmployeeInfo)(int nSerial,char *pName,char *pPhone);

HRESULT __stdcall (*UpdateEmployeeInfo)(int nSerial,char *pName,char *pPhone);

HRESULT __stdcall (*DeleteEmployeeInfo)(int nSerial);

(2.3)接下来加载动态库,ExtractFilePath(Application->ExeName)用来获取当前工程目录Debug的路径,LoadLibrary用来加载库,GetProcAddress用来根据动态库中的函数符号获取接口的地址,这些函数指针的用法与C语言中的回调函数完全一样;

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

hdll = NULL;

AnsiString str = ExtractFilePath(Application->ExeName) + "Project1.dll";

hdll = ::LoadLibrary(str.c_str());//动态加载

(FARPROC&)CreateEmployeeInfo = GetProcAddress(hdll, "CreateEmployeeInfo");

(FARPROC&)UpdateEmployeeInfo = GetProcAddress(hdll, "UpdateEmployeeInfo");

(FARPROC&)DeleteEmployeeInfo = GetProcAddress(hdll, "DeleteEmployeeInfo");

}

(2.4)对工程进行编译,一开始会报错,但是在工程目录下会生成Debug目录,把之前得到的DLL库放到Debug目录下,再次对工程进行编译即可;

(2.5)编程过程中可能需要经常对DLL工程的源码编辑再生成,如果一直用复制的方式很麻烦,可以在DLL工程右击->Options->Directories and Conditionals->Final OutPut Directory设置编译输出路径!

另外,具体的工程代码我已经放到CSDN下载区了,当然,具体工程的文件名称和文章中讲的会有出入,虽然会显得粗糙点,但对初学者还是可以借鉴的,http://download.csdn.net/detail/lushangqiushui/7140883,赚点积分!如果缺积分,也可以邮件讨要的(809873979@qq.com)!

对自己的小结:

一开始不懂要用C接口导出,以为要直接外部对类进行实例化,于是把DLL工程目录下的dll,lib和相应的头文件都复制到Project1的Debug目录下,就出现DLL中的类的成员函数都没有定义!其实要解决这个问题很简单,只要把Project1.lib附加到工程中就可以,但是主管的要求是只能用到DLL动态库,完全不涉及LIB或.h文件,而且做动态库主要是为了封装,外部是不可以用到DLL中的类,这说明我对封装的概念还是不了解,所以外部只能通过DLL导出的接口访问内部的一切!不过这次懂了,以后再写都是小意思了!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: