C++ Dll

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 " );
    
if NULL  ! =  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

你可能感兴趣的:(C++ Dll)