现在的位置: 首页 > 综合 > 正文

DLL:VS2005使用C++制作dll文件

2013年09月07日 ⁄ 综合 ⁄ 共 8031字 ⁄ 字号 评论关闭

c++制作dll文件

dll文件的c++制作
1、首先用vs2005建立一个c++的dll动态链接库文件,这时,
// DllTest.cpp : 定义 DLL 应用程序的入口点。
//

#include "stdafx.h"
//#include "DllTest.h"

#ifdef _MANAGED
#pragma managed(push, off)
#endif

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD ul_reason_for_call,
                       LPVOID lpReserved
           )
{
    return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif
这段代码会自动生成,
2、自己建一个DllTest.h的头文件,和DllTest.def的块声明文件。
其中头文件是为了声明内部函数使用。块声明主要是为了在dll编译成功后固定好方法名。别忘记添加#include "DllTest.h"
3、在DllTest.h中加入如下代码
#ifndef DllTest_01
#define DllTest_01
#define EXPORT extern "C" __declspec(dllexport)
//两个参数做加法
EXPORT int _stdcall Add(int iNum1=0,int iNum2=0);
//两个参数做减法
EXPORT int _stdcall Subtraction(int iNum1=0,int iNum2=0,int iMethod=0);
#endif
4、在DllTest.def中加入如下代码
LIBRARY    "DllTest"
EXPORTS
Add
Subtraction
5、在DllTest.cpp中写好代码为
// DllTest.cpp : 定义 DLL 应用程序的入口点。
//

#include "stdafx.h"
#include "DllTest.h"

#ifdef _MANAGED
#pragma managed(push, off)
#endif

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD ul_reason_for_call,
                       LPVOID lpReserved
           )
{
    return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif

//加函数
int APIENTRY Add(int a,int b)   // APIENTRY 此关键字不可少
{
return (a+b);
}
//减函数
int APIENTRY Subtraction(int a,int b,int i)
{
if(0==i)
    return (a-b);
else
    return (b-a);
}
6、这样编译生成就可以得到对应的DllTest.dll的文件了
二、C#调用dll文件
1、创建一个c#的控制台程序(当然其他也没有问题),自动生成以下代码
using System;
using System.Collections.Generic;
using System.Text;
//using System.Runtime.InteropServices;

namespace CSharpIncludeC__Dll
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}
2、添加命名空间using System.Runtime.InteropServices;
3、若要引用dll文件,首先吧dll文件自行拷贝到bin\debug,文件夹下,没有的话,先编译一下。
4、添加属性
[DllImport("DllTest.dll", CharSet = CharSet.Ansi)]
static extern int Add(int iNum1, int iNum2);
5、最终产生代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace CSharpIncludeC__Dll
{
    class Program
    {
        [DllImport("DllTest.dll", CharSet = CharSet.Ansi)]
        static extern int Add(int iNum1, int iNum2);

        [DllImport("DllTest.dll", CharSet = CharSet.Ansi)]
        static extern int Subtraction(int iNum1,int iNum2,int iMethod);

        static void Main(string[] args)
        {
            int iValue = Add(1, 2);
            Console.WriteLine(iValue);
            iValue = Subtraction(1, 2, 1);
            Console.WriteLine(iValue);
            Console.Read();
        }
    }
}
6、生成项目运行就可以了,结果是3和1

 

首先,我们写一个小小的例子

1.首先在VS2008中建立一个解决方案,在解决方案中新建一个项目,选择win32项目,再选择DLL,空项目。就建立了一个空的DLL项目,在头文件文件夹和源文件文件夹中分别建立firstdll.h和firstdll.cpp两个文件,我们将在firstdll.h文件中声明dll对外提供的函数的声明和类的定义。代码如下:

/*----------firstdll.h--------------------------------------------------------*/

#ifndef FIRSTDLL_H

#define FIRSTDLL_H

#ifdef DLLEXPORT

#define DLLOPTION _declspec(dllexport)    //表明标有此宏定义的函数和类是dll文件的导出函数和类,是dll文件的对外接口

#else

#define DLLOPTION _declspec(dllimport)       //表明标有此宏定义的函数和类的定义在dll文件中

#endif

class DLLOPTION CTest{

public:

virtual void sayHello();    //如果要在运行时动态链接导出类的成员函数必须声明为 virtual

};

extern "C" DLLOPTION CTest* getCTestInstance();      

#endif

/*-----------firstdll.cpp-----------------------*/ //为firstdll.h中的导出函数和导出类的成员函数提供具体实现

#include <iostream>

#define DLLEXPORT                    //定义了预处理器变量 DLLEXPORT

#include "firstdll.h"

using std::cout;

using std::endl;

void CTest::sayHello(){

cout << "Hello i come from dll"<<endl;

return;

}

CTest* getCTestInstance(){
return new CTest();
}

到此为止一个简单的dll文件所需要代码都有了,在项目上右键,选择生成,就会在解决方案的Debug文件夹下产生一个firstdll.dll动态链接库文件。

2.运行时动态链接的实现

首先,在同一个解决方案中建立一个新的win32项目。将firstdll.dll复制到项目文件夹下,再在IDE中将头文件添加项目中。编辑firstdll.dll文件将导出函数中要导出的成员函数改为virtual void sayHello()=0;(如果你是在加载时动态链接dll文件则不需要这么麻烦)

下面我们要编写运行时动态链接的代码了。我们在项目的源文件目录中建一个test.cpp文件。代码如下:

/*----------------test.cpp----------------------------------------------------------*/

#include <windows.h>
#include <iostream>
#include "firstdll.h"            //注意在导入firstdll.h文件之前,没有在声明DLLEXPORT 预处理器变量
#pragma   comment(linker,   "/subsystem:console ")          

  //告诉连接器,程序运行的方式是 win32 console.  /subsystem:console 是连接器选项
using std::cout;
using std::endl;

int main(){
LPWSTR lpws = L"firstdll.dll";
typedef CTest* (*dllProc)();        //定义一个函数指针类型,将来会用该类型的指针调用CTest* getCTestInstance()函数
HINSTANCE hdll = LoadLibrary(lpws);    //winapi 参数是dll文件的变量名/全路径名+变量名 。返回dll文件的句柄
if(hdll != NULL){

//winapi 利用dll句柄和导出函数的函数名得到函数的入口地址。返回 void* 所以要强转                                                                 

dllProc pdp = (dllProc)GetProcAddress(hdll,"getCTestInstance");    
CTest* pCTest = (pdp)();        //执行导出函数 返回指向CTest类的指针
pCTest->sayHello();             //利用类指针执行导出类的成员函数
delete pCTest;
FreeLibrary(hdll);         //望名生义 此winapi的作用是释放被动态链接到程序中的dll文件
cout << "the result of test is successful !!" <<endl;
}else{
cout << "Can not get handle of classdll.dll" << endl;
}
system("pause");
return 0;
}

第一次写的话难免出错比如创建项目是没有创建成win32 console application 而是 创建成 win32 application 可能会导致程序找不到入口所以显式的使用:#pragma   comment(linker,   "/subsystem:console ")

本人第一次写的时候还导致过访问冲突,结果是因为返回dll文件句柄的函数返回的是空。

发现程序不对了,可以调用GetLastError() api 返回错误的编号,然后在msdn中查找错误的原因。

如果调用不到dll文件中的导出函数,有可能是dll文件有问题。可以用"C:\Program Files\Microsoft Visual Studio\COMMON\Tools\DEPENDS.EXE"来查看dll文件的内容,这个

软件的使用方法我不是懂,我也就是看看那个函数在dll中到底有没有。

 

一. 编写 DLL
File/New/Dll 生成 Dll 的向导,然后可以添加导出函数和导出类
导出函数:extern "C" __declspec(dllexport) ExportType FunctionName(Parameter)
导出类:class __declspec(dllexport) ExportType ClassName{...}
例子:(说明:只是生成了一个 DLL.dll )

用于声明导入导出函数
__declspec(dllexport) 声明一个导出函数,一般用于dll中
__declspec(dllimport) 声明一个导入函数,一般用于使用某个dll的exe中

导出函式__declspec(dllexport)在dll中用
导入函式__declspec(dllimport)在要调用dll的程序中用

动态链接就不需要__declspec(dllimport)

#include "DllForm.h" // TDllFrm 定义

USERES("Dll.res");
USEFORM("DllForm.cpp", DllFrm);

class __declspec(dllexport) __stdcall MyDllClass { //导出类
public:
MyDllClass();
void CreateAForm();
TDllFrm* DllMyForm;
};

TDllFrm* DllMyForm2;
extern "C" __declspec(dllexport) __stdcall void CreateFromFunct();//导出函数

//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
return 1;
}
//---------------------------------------------------------------------------

MyDllClass::MyDllClass()
{
}

void MyDllClass::CreateAForm()
{
DllMyForm = new TDllFrm(Application);
DllMyForm->Show();
}
//---------------------------------------------------------------------------
void __stdcall CreateFromFunct()
{
DllMyForm2 = new TDllFrm(Application);
DllMyForm2->Show();
}

二. 静态调用 DLL
使用 $BCB path\Bin\implib.exe 生成 Lib 文件,加入到工程文件中
将该文件拷贝到当前目录,使用 implib MyDll.lib MyDll.dll 生成
// Unit1.h // TForm1 定义
#include "DllForm.h" // TDllFrm 定义
//---------------------------------------------------------------------------

__declspec(dllimport) class __stdcall MyDllClass {
public:
MyDllClass();
void CreateAForm();
TDllFrm* DllMyForm;
};
extern "C" __declspec(dllimport) __stdcall void CreateFromFunct();

class TForm1 : public TForm{...}

// Unit1.cpp // TForm1 实现
void __fastcall TForm1::Button1Click(TObject *Sender)
{ // 导出类实现,导出类只能使用静态方式调用
DllClass = new MyDllClass();
DllClass->CreateAForm();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{ // 导出函数实现
CreateFromFunct();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
delete DllClass;
}

三. 动态调用 DLL
// Unit1.h
class TForm1 : public TForm
{
...
private: // User declarations
void (__stdcall *CreateFromFunct)();
...
}

// Unit1.cpp // TForm1
HINSTANCE DLLInst = NULL;
void __fastcall TForm1::Button2Click(TObject *Sender)
{
if( NULL == DLLInst ) DLLInst = LoadLibrary("DLL.dll"); //上面的 Dll
if (DLLInst) {
CreateFromFunct = (void (__stdcall*)()) GetProcAddress(DLLInst,
"CreateFromFunct");
if (CreateFromFunct) CreateFromFunct();
else ShowMessage("Could not obtain function pointer");
}
else ShowMessage("Could not load DLL.dll");
}

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
if ( DLLInst ) FreeLibrary (DLLInst);
}

四. DLL 作为 MDIChild (子窗体) 【只编写动态调用的例子】
实际上,调用子窗体的 DLL 时,系统只是检查应用程序的 MainForm 是否为 fsMDIForm 的窗体,这样只

要把调用程序的 Application 的 Handle 传递给 DLL 的 Application 即可;同时退出 DLL 时也要恢复

Application

// MDIChildPro.cpp // Dll 实现 CPP
#include "unit1.h" // TForm1 定义
TApplication *SaveApp = NULL;
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
if ( (reason==DLL_PROCESS_DETACH) && SaveApp )
Application = SaveApp ; // 恢复 Application
return 1;
}

extern "C" __declspec(dllexport) __stdcall void TestMDIChild( //1024X768
TApplication* mainApp,
LPSTR lpCaption)
{
if ( NULL == SaveApp ) // 保存 Application,传递 Application
{
SaveApp = Application;

抱歉!评论已关闭.