C++ Programmer's Cookbook

{C++ 基础} {C++ 高级} {C#界面,C++核心算法} {设计模式} {C#基础}

C++ Dll

前言:为了介绍C#写界面,C++写算法的快捷开发方式,C#与C++的交互,首先介绍c++,C#内部的DLL,COM调用。

一, 静态的Lib:静态的lib经过编译后只有.h和.lib文件,没有dll,因为实现部分也包含在lib中,这就是与动态dll的区别。还有在写静态lib的时候不需要在使用导出关键字_declspec(dllexport)。一般有2中方法调用静态lib,如下实例:

静态lib:CPPLib->test.h

#pragma once

class CTest
{
public:
    CTest(void);
public:
    ~CTest(void);
public:
    
int Add(int x, int y);
    
int Square(int x);
};

//函数的实现必须写在.cpp文件中,否则编译有错,说重复定义
int Max(int x, int y);

静态lib的实现文件: CPPLib->test.cpp

#include "StdAfx.h"
#include 
"Test.h"

CTest::CTest(void)
{
}

CTest::~CTest(void)
{
}

int CTest::Add(int x, int y)
{
 return x
+y;
}
int CTest::Square(int x)
{
    return x
*x;
}

int Max(int x, int y)
{
    return x;
}


client调用CPPLibClient->CPPibClient.cpp

#include "stdafx.h"
//#include "test.h"
//#include <windows.h>
//#include <string>
//#include <assert.h>


//#include "../CppLib/test.h" 
//#pragma comment(lib,"../debug/CppLib.lib")
//#pragma 使用法


//#include "test.h"
//修改编译选项调用静态库
//需要修改:include的path,lib的path,和加入lib的名字,如下:
//C++->General->additional include directories
//Linker->General->additional library directories
//linker->input->additional dependencies

//不能动态加载静态的lib库
//HMODULE m_handle = LoadLibrary(L"../debug/CppLib.Lib");
//GetProcAddress(m_handle, "Max");
//FreeLibrary(m_handle);

int _tmain(int argc, _TCHAR* argv[])
{
    CTest test;
    
int a = test.Add(10,20);
    printf(
"the result is :%d\n",a);
    a 
= Max(10,20);
    printf(
"the result is :%d\n",a);
    return 
0;
    
}


调用方法:可以看出对于静态的只可以使用修改编译选项和pragma comment()来调用,不能使用loadlibrary()来调用。

二 ,动态DLL:在动态dll中,可以导出变量,函数和整个类。编译后有.h,.lib和dll文件,真正的实现包含在dll中,所以在client调用动态dll的时候,必须要使用dll,最后和client的放在同意目录下。要导出必须使用导出关键字_declspec(dllexport)。有时还使用extern “C”,为了使导出能够与C兼容,一般我们都加extern “c”。
一般调用有3中方法,实例如下:

实例1:演示了导出变量和函数,和前2中调用方法,修改编译选项和pragma comment().
动态dll:CPPdll->test.h

#pragma once


extern 
"C" _declspec(dllexport) int nCppDll;
extern 
"C" _declspec(dllexport) int fnCppDll(void);

extern 
"C" _declspec(dllexport) int Max(int a, int b);
extern 
"C" _declspec(dllexport) int Min(int a, int b);


动态dll的实现:CPPDLL->test.cpp

#include "StdAfx.h"
#include 
"Test.h"


// This is an example of an exported variable
 
int nCppDll=100;

// This is an example of an exported function.
int fnCppDll(void)
{
    return 
42;
}

int Max(int a, int b)
{
if(a>=b)return a;
else
return b;
}
int Min(int a, int b)
{
if(a>=b)return b;
else
return a;


client的调用:cppclient->cppclient.cpp

#include "stdafx.h"

#pragma comment(lib, 
"../debug/CppDll.lib")
extern 
"C"  int Max(int a,int b);//_declspec(dllimport)
extern 
"C" int Min(int a,int b); //_declspec(dllimport)
extern 
"C" _declspec(dllimport) int nCppDll;
extern 
"C" int fnCppDll(void);

//#include "test.h"
//修改编译选项调用静态库
//需要修改:include的path,lib的path,和加入lib的名字,如下:
//C++->General->additional include directories
//Linker->General->additional library directories
//linker->input->additional dependencies

int _tmain(int argc, _TCHAR* argv[])
{
    
int a;
    a  
=Min(8,10);
    printf(
"比较的结果为 %d\n",a);
    a
= Max(8,10);
    printf(
"比较的结果为%d\n",a);
    
    printf(
"导出的变量:%d\n",nCppDll);

    a 
= fnCppDll();
    printf(
"fnCppDll的结果:%d\n",a);    

    return 
0;
}

上面演示了对一般变量和函数的导出的调用方法中的其中的2中,修改编译选项和pragma comment(),当使用pragma comment()的使用,应当注意:
使用#pragma隐式加载动态库
对于变量,必须申明且不能include头文件。extern "C" _declspec(dllimport) int nCppDll;
对于函数,或include头文件,或是申明。extern "C" int fnCppDll(void);
对于类,最好使用函数封装导出指针供使用。
参考:http://www.cppblog.com/mzty/archive/2006/07/24/10419.html

实例2:演示类的导出和使用动态加载来调用。

动态dll的类导出:CPPDll2->test.h

#pragma  once
//#include "boost/shared_ptr.hpp"

class Test 
{
public:
 virtual ~Test() {}
 virtual void DoIt() 
=0;
};

//extern "C" _declspec(dllexport)  std::auto_ptr<Test> CreateTest();
//extern "C" _declspec(dllexport) boost::shared_ptr<Test> CreateTest();
extern 
"C" _declspec(dllexport) Test* CreateTestPtr();

extern 
"C" _declspec(dllexport) void DeleteTestPtr(Test*);


动态dll的类导出的实现:CPPDll2->test.cpp

//test.cpp
#include 
"stdafx.h"
#include 
"Test.h"
#include 
<stdio.h>
//#include <memory>
//#include "boost/shared_ptr.hpp"


class CTest : 
public Test
{
public:
    virtual void DoIt()
   { printf(
"Should do something\n"); }
};

//std::auto_ptr<Test> CreateTest()
//{
//    return std::auto_ptr<Test>(new CTest);
//}


//boost::shared_ptr<Test> CreateTest() 
//
//    return boost::shared_ptr<Test>(new CTest);  
//}

Test
* CreateTestPtr()
{
    return 
new CTest();
}

void DeleteTestPtr(Test
* t)
{
    
if(t != NULL)
    {
        delete t;
        t 
= NULL;
    }

}

对loadlibrary的分装,可以作为tools:

//library.h
#pragma once
#include 
<windows.h>
#include 
<string>
#include 
<assert.h>

class Library
{
public:

 
explicit Library(const wchar_t* name)
 {
  m_handle 
= LoadLibrary(name);
  assert(m_handle);
  
if (!m_handle)
   throw std::runtime_error(std::
string("Could not find library file:"));  
 }

 ~Library()
 {
  FreeLibrary(m_handle);
 }

 void
* GetProc(const char* name)
 {
  void
* proc = ::GetProcAddress(m_handle, name);
  assert(proc);
  return proc;
 }

private:
 HMODULE m_handle;
};


client的调用:


#include 
"stdafx.h"
#include 
"library.h"
#include 
"../CppDll2/test.h"

int _tmain(int argc, _TCHAR* argv[])
{
    
    typedef Test
* (*CREATE)();
    typedef void (
*DEL)(Test*);    

    Library lib(L
"CppDll2.dll");
    
//std::auto_ptr<Test> test = ((std::auto_ptr<Test> ) lib.GetProc("CreateTest"));
    Test
* test = (((CREATE)(lib.GetProc("CreateTestPtr")))());
    test
->DoIt();
    ((DEL)(lib.GetProc(
"DeleteTestPtr")))(test);
    return 
0;
}


上面的是对类的动态调用,注意需要include头文件哦!
//通过API动态加载动态库
//对于类的导出,最好使用函数封装,导出类的指针。
//动态加载dll, 如果导出的函数只使用 extern,而没有使用extern "C" 则GetProcAdress会找不到函数的指针,要想找到可以使用真正要找的函数原型哦,可能是函数名后加@@。。。,也可以使用编号来找到需要的函数地址。
//但是如果导出函数使用extern "C"的话,导出函数的返回值不能是auto_ptr<>或shared_ptr<>哦,但是我们仍然可以使用智能指针哦,采用的方法是不使用return返回,使用函数的参数返回哦。//使用智能指针导出的更好的实现,请参考 http://www.cppblog.com/eXile

//参考: http://www.cppblog.com/eXile/archive/2007/04/19/22262.html

//更多dll类型:http://www.vckbase.com/document/viewdoc/?id=1116

//调用约定:http://blog.chinaunix.net/u/21790/showart_265932.html


三 资源DLL

在C++中,我们可以建立纯资源的动态dll,比如说我们建立了一个动态的资源dll,里面增加一个string: id为IDS_APPLICATION,值为:aaa,
则我们可以在client动态调用如下:

#include "stdafx.h"
#include 
<windows.h>
#include 
"../ResDll/resource.h"

int _tmain(int argc, _TCHAR* argv[])
{
    HMODULE hModule
=LoadLibrary(L"../debug/ResDll.dll");
    
ifNULL != hModule)
    {
        TCHAR szName[
200];
        ::LoadString(hModule,IDS_APPLICATION,szName,
200);
        FreeLibrary(hModule);
    }
    return 
0;
}


资源还可以是其他的比如是icon,bitmap。。。。等,有对应的load。()函数去调用。

四,总结

熟悉dll调用的3中方法,其中对静态的调用只有2中方法,一般对类的导出调用要使用函数封装哦!:~


代码下载:http://www.cppblog.com/Files/mzty/DLLTest.rar

posted on 2007-05-28 09:59 梦在天涯 阅读(7826) 评论(1)  编辑 收藏 引用 所属分类: CPlusPlus

评论

# re: C++ Dll 2007-06-22 12:26 .net编程

好东西  回复  更多评论   


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

EMail:itech001#126.com

导航

统计

  • 随笔 - 461
  • 文章 - 4
  • 评论 - 746
  • 引用 - 0

常用链接

随笔分类

随笔档案

收藏夹

Blogs

c#(csharp)

C++(cpp)

Enlish

Forums(bbs)

My self

Often go

Useful Webs

Xml/Uml/html

搜索

  •  

积分与排名

  • 积分 - 1633320
  • 排名 - 5

最新评论

阅读排行榜