Windows 7 上动态库开发

来源:互联网 发布:知乎怎样发表文章 编辑:程序博客网 时间:2024/05/16 06:04

准备工作:

建立文件夹F:\pule

以后所有操作都在文件夹pule中



建立好的文件夹视图。

其中puleDll作为Dll开发目录

puleMain则是Main函数,调用puleDll中的函数来测试。


DLL工程的建立

1.创建puledll工程,

打开VC6.0, 文件-->新建-->工程,选择win32 dynamic-Link Library, 左边填写文件名pule: 如下图



确定之后,选择“一个可以导出某些符号的dll工程”, 再点击 完成---确定(如下图)



2此时查看工作空间,如下:



我们要做纯C开发,所以,把这里的CPP后缀全部改成.c,; 也就是把pule.cpp 改成pule.c

而且不需要预编译头,也就是删除StdAfx.h 和StdAfx.cpp

此时的工作空间如下:



这时编译是过不了的,出现:f:\pule\puledll\pule\pule.c(4) : fatal error C1083: Cannot open precompiled header file: 'Debug/pule.pch': No such file or directory错误

这是因为我们删除了预编译头文件,也就是stdafx.h 和stdafx.cpp, 只需要设置下工程选项:

工程-->设置-->c/c++

在c/c++标签下,“分类” 中选择预编译的头文件, 选择 “不使用预补偿页眉", 确定就可以了。




此时再编译还是过不了:



这是因为我们把pule.cpp后缀编成了.c, 由于VC认为以.c为后缀的是纯C代码, C语言是没有类的, 所以, pule.h 定义的那个类就有问题了,解决此问题的方法 就是直接删除关于类的定义。

删除之后的代码如下:

pule.h:

#ifdef PULE_EXPORTS#define PULE_API __declspec(dllexport)#else#define PULE_API __declspec(dllimport)#endifextern PULE_API int nPule;PULE_API int fnPule(void);



pule.c

// pule.c : Defines the entry point for the DLL application.//#include "pule.h"#include <windows.h>BOOL APIENTRY DllMain( HANDLE hModule,                        DWORD  ul_reason_for_call,                        LPVOID lpReserved ){    switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;    }    return TRUE;}// This is an example of an exported variablePULE_API int nPule=0;// This is an example of an exported function.PULE_API int fnPule(void){return 42;}

可以看出上面还加了一行#include<windows.h>

开发win32程序当然得包含windows.h了, 以前这个文件是包含在stdafx.h中的, 现不需要这个文件,所以就得自己包含windows.h了


完成以设置后,点击生成,就会在pule\debug\中生成pule.dll和pule.lib


3.动态链接库制作与链接原理:

可以看到,要想让动态链接库里的函数能被其他程序调用,必需在声明作如下声明:

PULE_API int fnPule(void);
PULE_API是必要的, 以后自己写的函数,想导出,就要依照这个写。


再看生成的文件:

pule.dll就是动态链接库了, 这个库里是程序代码, 编译好的二进制形式。

再看pule.lib, 这个不是静态库, 是编译时需要的库。

如果在另一个程序中调用pule.dl中的函数, 则在链接时需要函数信息,这些信息放在pule.lib中,链接完成后,这个库就没用了, 只要pule.dll就可以运行程序。


测试程序puleMain工程的建立

建立这个工程的目的是调用上一个工程的dll中的函数,以测试上一个工程是不是能正确运行

这个工程是一个普通的win32 Console Application工程

1.创建puleMain工程

打开VC6.0: 文件-->新建-->工程-->win32 Console Application





建立好工程后,再新建一个puleMain.c文件,加入工程中:

文件-->新建-->文件-->C++ Source File ; 文件名取puleMain.c 注意,必须是.c 




建立好文件之后,写一个hello world程序, 测试是不是可以正常运行:


如果正常运行就没有问题了。


在测试工程中调用dll工程中的函数:

1.把dll工程的输出目录改为测试工程的输出目录:

现在可以看到,有两个Debug目录:

分别是puledll\pule\debug

            pulemain\pulemain\debug

如果puleMain.exe中使用了动态连接库pule.dll, 则pule.dll必须和puleMain.exe在同一个目录中(也有其他方法,把pule.dll入在c:\windows\system32中).

在puledll工程中做如下设置,让此工程编译链接时把pule.dll,pule.lib自动生成到pulemain]pulemain\debug中:

在puledll工程中:工程-->设置-->常规-->输出目录:..\..\puleMain\puleMain\Debug



这时再编译生成puledll工程,打开测试工程的Debug目录,可以看到已经有了pule.dll和pule.lib



2.在测试工程puleMain中调用pule.dll中的fnPule();函数

这是需要添加pule.h头文件

#include<stdio.h>#include"..\..\puleDll\pule\pule.h"  //加上头文件int main(){printf("%d\n", fnPule());        //调用dll函数printf("Hello world!\n");return 0;}

此时编译链接会失败,回为链接时找不到fnPule()的定义

再设置链接器选项:工程-->设置-->连接:选择“分类"的常规, 在对象/库模块中加入Debug\pule.lib

也就是在puleMain\puleMain\Debug\中要有pule.lib, 这个在上几步中已经生成了。



确定之后,编译运行应该没有错误了,运行了如下:



可以看到输出了42,表示运行成功了。


在puledll中使用netsnmp的库进行开发


准备工作:

在puledll文件夹下建立net-snmp文件夹,把net-snmp编译安装开发版的库和头文件复制到这个文件夹下

这个需要编译安装net-snmp-5.7.2. 安装时选择安装开发库,这时会在C:\usr下有lib和include两个目录。copy到这里。





可以看到lib文件夹下有四个库, netsnmp.lib  netsnmpagent.lib netsnmpmibs.lib netsnmptrapd.lib

以下所有操作均在puledll项目中操作:

在pule.c中加入以下头文件:

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/utilities.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/library/snmp_transport.h>

并且在 int fnPule(void)函数中调用了init_snmp("snmpapp");

// pule.c : Defines the entry point for the DLL application.//#include "pule.h"#include <net-snmp/net-snmp-config.h>#include <net-snmp/utilities.h>#include <net-snmp/net-snmp-includes.h>#include <net-snmp/agent/net-snmp-agent-includes.h>#include <net-snmp/library/snmp_transport.h>BOOL APIENTRY DllMain( HANDLE hModule,                        DWORD  ul_reason_for_call,                        LPVOID lpReserved ){    switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;    }    return TRUE;}// This is an example of an exported variablePULE_API int nPule=0;// This is an example of an exported function.PULE_API int fnPule(void){init_snmp("snmpapp");return 42;}


这些头文件是开发snmp的必要头文件,加入后编译将会产生很多错误, 下面一一解决



1.第一个错误是找不到以上几个头文件:



设置头文件搜索路径:

在工程-->选项-->c/c++:分类:常规中

下边有: 工程 选项, 在最后加入  /I../net-snmp/include

这是告诉编译器到../net-snmp/include目录中查找头文件

在准备工作我们已经将对应的头文件复制到net-snmp目录中了,所以这样设置就可以找到头文件了。




2.出现许多redifinition错误:


看到有ws2tcpip.h有重复定义, 这时要去掉#include<windows.h>

再做如下修改:

PULE_API int fnPule(void)
{
init_agent("snmpagent");
return 42;
}

在这个函数中加入init_agent("snmpagent")



3.链接错误:找到不init_agent 



这是因为在链接时找不到init_agent,这个函数在准备工作时复制的那4个库中, 所以这次需要修改链接选项:

工程-->设置-->连接:分类:输入

在附加库路径中加入:  ..\net-snmp\lib

在工程选项中加入以下4个库:netsnmp.lib  netsnmpagent.lib netsnmpmibs.lib netsnmptrapd.lib



4.MSVCRT.lib(MSVCRT.dll)与LIBCMTD.lib冲突



此时只需要取消默认连接的库LIBCMTD.lib

原因是使用多线程的库msvcrt.lib中有好多函数在单线程的libcmtd.lib中也有,所以只留下一个库msvcrt.lib就可以了:

操作方法:工程-->选项-->连接-:分类:输入:

在忽略库中加入:libcmtd.lib




5.没有连接winsocket相关的库:



解决方法:

链接选项中加入WS2_32.LIB库

操作方法:工程-->选项-->连接-:分类:输入:

在工程选项中加入ws2_32.lib



至次所有错误都已经排除,应该可以生成dll了。

在测试工程puleMain中运行:得到如下结果,可以看出init_snmp("snmpapp")正确运行了。 



注意:不要包含stdafx.h头文件。

这以后就可以使用net-snmp提供的4个库进行snmp开发了。

如何自成snmp中的这四个库以及开发所需要的头文件,见我的另一片博文。


注意2:使用net-snmp的四个库, 必须要有MIB, 默认MIB位置在:

C:\usr\share\snmp\mibs

需要根据自己编译安装net-snmp选择位置安装MIB.




1 0
原创粉丝点击