社区
进程/线程/DLL
帖子详情
用VC2003生成DLL的时候,为什么def文件不能导出函数?
xyx119
2006-12-28 05:24:53
用VC6还好好的,用.net就是导不出来,是怎么回事啊?
各位朋友,指点一下啊!
...全文
146
2
打赏
收藏
用VC2003生成DLL的时候,为什么def文件不能导出函数?
用VC6还好好的,用.net就是导不出来,是怎么回事啊? 各位朋友,指点一下啊!
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
2 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
xyx119
2006-12-28
打赏
举报
回复
结贴了!我知道了!
在属性页----->链接器------->输入------->模块定义文件!
哎!!!!!!!!!!!!!!!!
YouTuBe
2006-12-28
打赏
举报
回复
Up
VC++使用
DEF
文件
导出
函数
摘要:VC/C++源码,系统相关,
DEF
,
导出
函数
VC++使用
DEF
文件
导出
函数
,
DEF
导出
函数
以
DLL
文件
的形式,最终编译后
生成
DLL
文件
,下载包内为源码
文件
包。
MingW VC 之.a .lib .
dll
.
def
关系
MSVC vs. MinGW 之 (lib,
dll
,
def
,obj,exe) vs (a,
dll
,
def
,o,exe) 玩转攻略手记 一份粗糙的研究记录,有待补完和整理。 MinGW: c -> o gcc -c a.c c -> exe gcc a.c libs.o -o a.exe (从主程序a.c,附加libs,
生成
a.exe) o -> exe gcc a.o b.o ... -o main.exe c ->
dll
,
def
,a gcc a.c -shared -o a.
dll
-Wl,--output-
def
,a.
def
,--out-implib,liba.a a ->
dll
a2
dll
liba.a
dll
-> a:
dll
tool --
dll
name a.
dll
--
def
a.
def
--output-lib liba.a (需要
def
文件
) a ->
def
: dumpbin /exports lib.a > lib.
def
(在windows上调用,
def
需要修改)
dll
->
def
: pexports a.
dll
-o > a.
def
(这里的-o是指给
函数
标序号) lib ->
def
: reimp -d a.lib lib -> a: (for __cdecl functions in most case) reimp a.lib; (for __stdcall functions) MSVC: c -> lib cl /LD a.c (注意已经定义了export列表) c ->
dll
cl /LD a.c c -> obj cl /c a.c c -> exe cl a.c /out:a.exe
dll
->lib lib /machine:ix86 /
def
:a.
def
/out:a.lib (需要
def
文件
) obj ->lib lib a.obj b.obj... /out:mylib.lib
dll
->
def
DUMPBIN a.
dll
/EXPORTS /OUT:a.
def
(
生成
的
def
需要做修正) lib ->
def
reimp -d a.lib (这个要在MSYS+MinGW下用) 关于这些工具的适用范围可以很容易的理解和记忆。
dll
和exe都是PE
文件
,所以可以使用pexports. lib和a是静态库
文件
,都是归档类型,不是PE格式。所以
不能
使用pexports.
dll
可以使用
dll
tool. lib可以使用lib, 和reimp(lib->a工具) 所有的bin
文件
,包括
dll
,exe,lib,a都可以使用dumpbin. 参考: http://hi.baidu.com/kaien_space/blog/item/5e77fafa2ba9ff16a8d3110a.html Mingw官网文档: http://www.mingw.org/wiki/MSVC_and_MinGW_
DLL
s http://oldwiki.mingw.org/index.php/CreateImportLibraries http://www.mingw.org/wiki/FAQ http://hi.baidu.com/opaquefog/blog/item/9b21b6deb324e25dccbf1ab7.html http://qzone.qq.com/blog/8330936-1238659272 http://hi.baidu.com/jzinfo/blog/item/b0aa1d308de99f9da8018e00.html 本篇测试用代码: 1. main.cpp #include #include #include "mylib.h" using namespace std; int main() { char str[]="Hello world!"; printhello(str); return 0; } 2. mylib.cpp #include #include #include "mylib.h" using namespace std; void EXPORT printhello(char *str) { cout << str << endl; } 3. mylib.h #
def
ine EXPORT __declspec(
自己写的
dll
的简介
为何
DLL
先看看静态库与
DLL
的不同之处 可执行
文件
的
生成
(Link期):前者很慢(因为要将库中的所有符号定义Link到EXE
文件
中),而后者很快(因为后者被Link的引入库
文件
无符号定义) 可执行
文件
的大小:前者很大,后者很小(加上
DLL
的大小就和前者差不多了) 可执行
文件
的运行速度:前者快(直接在EXE模块的内存中查找符号),后者慢(需要在
DLL
模块的内存中查找,在另一个模块的内存中查找自然较慢) 可共享性:前者不可共享,也就是说如果两个EXE使用了同一个静态库,那么实际在内存中存在此库的两份拷贝,而后者是可共享的。 可升级性:前者不可升级(因为静态库符号已经编入EXE中,要升级则EXE也需要重新编译),后者可以升级(只要接口不变,
DLL
即可被升级为不同的实现) 综合以上,选择静态库还是
DLL
1. 静态库适于稳定的代码,而动态库则适于经常更改代码(当然接口要保持不变),当
DLL
更改(仅实现部分)后,用户不需要重编工程,只需要使用新的
Dll
即可。 2. 由于静态库很吃可执行
文件
的
生成
(Link期)时间,所以如果对可执行
文件
的Link时间比较敏感,那么就用
DLL
。 使用
DLL
在介绍如何创建
DLL
之前,让我们先了解它是如何被使用的。 1. 显式调用(也叫动态调用) 显 示调用使用API
函数
LoadLibrary或者MFC提供的AfxLoadLibrary将
DLL
加载到内存,再用GetProcAddress()在 内存中获取引入
函数
地址,然后你就可以象使用本地
函数
一样来调用此引入
函数
了。在应用程序退出之前,应该用FreeLibrary或MFC提供的 AfxLoadLibrary释放
DLL
。 下面是个显示调用的例子,假定你已经有一个Test.
dll
,并且
DLL
中有个
函数
名为Test,其声明式是void(); #include < iostream > using namespace std; type
def
void(*TEST )(); int main( char argc, char* argv[] ) { const char*
dll
Name = "Test.
dll
"; const char* funcName = "Test"; HMODULE h
DLL
= LoadLibrary(
dll
Name ); if ( h
DLL
!= NULL ) { TEST func = TEST( GetProcAddress( h
DLL
, funcName ) ); if ( func != NULL ) { func(); } else { cout << "Unable to find function \'" << funcName << "\' !" << endl; } FreeLibrary( h
DLL
); } else { cout << "Unable to load
DLL
\'" <<
dll
Name << "\' !" << endl; } return 0; } 注意 1. 显示调用使用GetProcAddress,所以只能加载
函数
,无法加载变量和类。 2. 此外GetProcAddress是直接在.
dll
文件
中寻找同名
函数
,如果
DLL
中的Test
函数
是个C++
函数
,那么由于在.
dll
文件
中的实际
文件
名会被修饰(具体被修饰的规则可参考
函数
调用约定详解或者使用VC自带的Depends.exe查看),所以直接找Test是找不到的,这时必须把
函数
名修改为正确的被修饰后的名称,下面是一种可能(此
函数
在
DLL
中的调用约定为__cdecl): const char* funcName = "?Test@@YAXXZ"; 2. 隐式调用(也叫静态调用) 隐式调用必须提供
DLL
的头
文件
和引入库(可以看作轻量级的静态库(没有符号定义,但是说明了符号处于哪个
DLL
中))。 有了头
文件
和引入库,
DLL
的使用就跟普通静态库的使用没啥区别,只除了
DLL
要和EXE一起发布。 显示调用与隐式调用的优缺点 显示调用使用复杂,但能更加有效地使用内存,因为
DLL
是在EXE运行时(run time)加载,必须由用户使用LoadLibrary和FreeLibrary来控制
DLL
从内存加载或卸载的时机。此外还可以加载其他语言编写的
DLL
函数
。 静态调用使用简单,但
不能
控制
DLL
加载时机,EXE加载到内存同时自动加载
DLL
到内存,EXE退出时
DLL
也被卸载。 创建
DLL
下面我们着重讲解如何在VC下创建
DLL
首先要建立一个Win32的
DLL
工程。再把普通静态库的所有
文件
转移到
DLL
工程中,然后: 为所有的类声明加上__declspec(
dll
export)关键字,这有这样编译器才能自动为你产生引入库
文件
(否则你需要自己写.
def
文件
来产生,因为不常用所以在此不再阐述其细节) 对于
DLL
的用户来讲,类声明就需要用另外一个关键字__declspec(
dll
import)(此关键字对于类和
函数
而言并非必须,但对于变量而言则是必须的)。所以通常我们会定义一个宏来包装之,比如 #if
def
MY
DLL
_EXPORTS #
def
ine MY
DLL
_API __declspec(
dll
export) #else #
def
ine MY
DLL
_API __declspec(
dll
import) #endif 这样我们就能写出如下的类 class MY
DLL
_API MyClass { ... }; 当然在创建
DLL
的工程里需要包含preprocessor(预处理指示器)MY
DLL
_EXPORTS,而在用户工程里面则不应该包含MY
DLL
_EXPORTS。 其实上面说的VC早就帮我们做好了。如果你创建的
DLL
工程叫做Test,那么此工程自动包含TEST_EXPORTS。如果你在创建工程的时候选择了Exprot Symbols, 那么VC还会自动帮你创建一个示例
文件
Test.h,此
文件
定义出 #if
def
TEST_EXPORTS #
def
ine TEST_API __declspec(
dll
export) #else #
def
ine TEST_API __declspec(
dll
import) #endif 你自定义的
文件
都应该包含此
文件
以使用TEST_API。(如果没有选择Exprot Symbols,那么就得自己动手写出这段宏了) 示例
文件
中还包括了一个类,变量,以及全局
函数
的写法 class TEST_API CTest { public: CTest(void); // TODO: add your methods here. }; extern TEST_API int nTest; TEST_API int fnTest(void); 通过上面的示例我们也可以看出全局(或者名字空间)变量和
函数
的声明方法 细节讨论 1.
DLL
的入口
函数
Dll
Main并非必须,如果没有它,编译器会帮你自动
生成
一个不做任何事的
Dll
Main。 2. 如果是可以定义在头
文件
里面的东西:包括宏,常量,内联
函数
(包括成员内联
函数
)以及模板。那么在
DLL
中的定义中可以不必包含TEST_API,和普通的定义没有区别。 如果一个类完全由内联
函数
和纯虚
函数
构成,那么也不需要TEST_API这样的关键字。一个不带成员
函数
的struct也一样。 3. 所有未经__declspec(
dll
export)
导出
的类都只能作为
DLL
内部类使用。当然外部仍然可以使用其内联成员
函数
(前提是该成员
函数
不应该调用任何未经
导出
的
函数
或者类成员
函数
) 发布
DLL
1. 程序库的作者应该将三件套:头
文件
,引入库
文件
和
DLL
一同发布给用户,其中头
文件
和引入库是专为静态调用的用户准备,也就是C/C++用户。(此外有些
DLL
内部使用的头
文件
,如果没有被接口头
文件
直接#include,那么该头
文件
就不必发布,这和静态库是一样的)。 2.
DLL
的用户只需将
DLL
和可执行程序一同发布即可。 C++程序使用C语言
DLL
(静态库规则一样) C不存在class, 所以由C创建的
DLL
必然也不会出现class;对于全局变量的使用C和C++没有什么不同,所以我们把焦点集中在全局
函数
上(此外全局变量的规则一样)。 我们知道C++程序要使用C语言的
函数
就必须在
函数
声明前加上extern "C"关键字,这对于静态库和
DLL
没有什么不同。 但是这个关键字
不能
直接出现在头
文件
函数
声明中,否则
DLL
无法通过编译, 原因很简单,C语言并没有extern "C"这个关键字。 1. 一种作法是把C向C++迁移的责任交给
DLL
创建者。定义出一个宏,以使
DLL
(C工程)中不出现extern "C"或者只是extern,而在用户工程(C++工程)中保持原样。幸运的是windows早已为我们设计好一切,这个宏就是EXTERN_C(存在于 winnt.h中) : #if
def
__cplusplus #
def
ine EXTERN_C extern "C" #else #
def
ine EXTERN_C extern #endif 注意上面必须是extern而不是空。因为虽然C的
函数
声明不是必须添加extern,但是变量声明则必须添加extern。 有了EXTERN_C,在头
文件
中这样定义
函数
: EXTERN_C TEST_API int fnTest(void); 2. 另外一种做法是把把C向C++迁移的责任交给用户,用户在包含
DLL
头
文件
的时候以extern "C"来include: extern "C" { #include "my
dll
.h" #include "my
dll
core.h" ... } 可以把上述的extern "C"段放在新的头
文件
中和
DLL
一起发布,这样C++用户只需要包含这个头
文件
就可以了。比如Lua库就自带了一个etc/lua.hpp
文件
。通常此
文件
会由
DLL
作者提供,所以此时迁移的责任仍在
DLL
创建者。 注意用户不要试图以extern "C"来重新声明
函数
,因为重复声明是允许的,但是必须保证和头
文件
中的声明相同。 3. 这种做法的一个变形就是直接在C头
文件
中以extern "C"将所有
函数
和变量声明包含之,这样就无需像上面那样多提供一个额外的头
文件
了。通常像这样(my
dll
头
文件
): #include 头
文件
段 #if
def
__cplusplus extern "C" { #endif
函数
和变量声明 ... #if
def
__cplusplus } #endif 创建标准的
DLL
,使其可被其他语言使用 通常我们会希望
DLL
能够被其他语言使用,因而我们的
DLL
往往不会提供类定义,而只提供
函数
定义。(因为许多编程语言是不支持类的)。 此时
函数
的调用约定必须是__stdcall(在vc下默认是__cdecl,所以你不得不手工添置),因为大部分语言不支持__cdecl,但支持__stdcall(比如VBScript,Delphi等)。 此外我们希望
导出
到
DLL
中的
函数
名能够更易被识别(用户使用才会更方便),也就是说
DLL
应该编译出无修饰的C
函数
名。 所以我们可能会 1. 如果你只用C语言,那么必然以C
文件
创建
DLL
(自动编出C符号名),考虑到潜在的C++用户(此类用户多以静态调用方式使用
DLL
,因而需要看到其
函数
声明),我们还需要使用EXTERN_C关键字(详见上面的讨论)。 2. 如果你使用C++,那么必然以C++
文件
创建
DLL
,这时你应该直接以extern "C"修饰。 结论 所以要创建能够为任意编程语言使用之
DLL
,我们应该 1. 只创建
函数
2. 声明__stdcall调用约定(或者WINAPI,CALLBACK,前提是你必须包含windows头
文件
) 3. 以CPP
文件
+ extern "C" 或者 C
文件
+ EXTERN_C 4. 当然还需要
DLL
_API的声明(如果光有
dll
export,那么
DLL
也只能被显示调用)。 更完美一点 不应该使用
dll
export和extern "C"而应该使用.
def
文件
。虽然经过上面的4个步骤,我们的
DLL
里面的C
函数
名已经相当简洁了,但仍不是最完美的:比如一个声明为function的
函数
,实际在
DLL
中的名字确可能是function@#。而使用.
def
文件
,我们可以让
DLL
中的
函数
名和声明的
函数
名保持一致。 关于.
def
的详细用法可参考: 微软
DLL
专题 使用
DEF
文件
从
DLL
导出
在
DLL
与静态库之间切换 前面我曾经提到对于使用
DLL
的用户__declspec(
dll
import)关键字可有可无,当然前提是
DLL
中不包括变量定义。 所以要把库既能够做成
DLL
,也能够做成静态库,那么就应该作出类似下面这样的定义: 1.
DLL
不包括变量的定义 #if
def
TEST_EXPORTS #
def
ine TEST_API __declspec(
dll
export) #else #
def
ine TEST_API #endif 然 后只要把工程的配置属性(Configuration Type)简单地在Static Library (.lib)或者Dynamic Library (.
dll
)切换即可(VC会自动地为
DLL
添加预处理器TEST_EXPORTS,为静态库取消TEST_EXPORTS)。 2.
DLL
包含变量定义,也是标准的做法 #if
def
TEST_BUILD_AS_
DLL
#if
def
TEST_EXPORTS #
def
ine TEST_API __declspec(
dll
export) #else #
def
ine TEST_API __declspec(
dll
import) #endif #else #
def
ine TEST_API #endif 如果要将库做成
DLL
,那么需要
DLL
创建者添加预处理器TEST_BUILD_AS_
DLL
和TEST_EXPORTS,后者通常由编译器自动添加;如果做成静态库则不需要添加任何预处理器。 用户则可以通过添加或取消TEST_BUILD_AS_
DLL
来使用动态库或静态库。 对于
DLL
的用户,TEST_BUILD_AS_
DLL
这个名称似乎起得不好。下面的做法或许会更合理些: #if
def
ined(TEST_API) #error "macro alreday
def
ined!" #endif #if
def
ined(TEST_BUILD_
DLL
) &&
def
ined(TEST_USE_
DLL
) #error "macro conflict!" #endif #if
def
ined(TEST_BUILD_
DLL
) // build
dll
#
def
ine TEST_API __declspec(
dll
export) #elif
def
ined(TEST_USE_
DLL
) // use
dll
#
def
ine TEST_API __declspec(
dll
import) #else // build or use library, no preprocessor needs #
def
ine TEST_API #endif 相关链接 微软
DLL
专题 Windows API编程之动态链接库(
DLL
)
AheadLib源代码
一、简介 AheadLib 是用来
生成
一个特洛伊
DLL
的工具,用于分析
DLL
中的
函数
参数调用(比如记录Socket send了什么等等)、更改
函数
功能(随心所欲了:)、更改界面功能(比如在Hook里面
生成
一个按钮,截获事件等等)。 二、使用 1.用 AheadLib 打开要模拟的
DLL
,
生成
一个 CPP
文件
。 2.用 Visual Studio 6.0/.NET 建立一个
DLL
工程,把这个 CPP
文件
加入到项目中。 3.使用 Release 方式编译,
生成
的
DLL
将和原来的
DLL
具有一模一样的
导出
函数
,并且能顺利把这些
函数
转发到原来的
函数
中。 4.AheadLib 还可以
生成
Hook 代码,用于截取当前进程的所有消息,这样就可以随心所欲地处理各种消息了 (修改第三方程序界面功能的好助手)。 三、备注 1.如果
导出
函数
过多,在 Visual Studio 6.0 中,如果出现编译错误,请在项目属性关闭与编译头功能。 2.如果是 C++ 、C __stdcall、C __fastcall 的方式
导出
的话,
生成
的
函数
声明将会还原成原代码级别(可能需要修改才能编译,比如
导出
C++类的情况)。此时使用 __declspec(
dll
export)
导出
——
不能
指定
导出
序号。 3.如果是 NONAME 或者 C _CDECL 方式
导出
(比如
DEF
导出
,大多数Windows
DLL
都是这种情况,比如WS2_32等等),则使用#pragma comment(linker, "/EXPORT:...)
导出
,且指定
导出
序号。 4.如果系统中没有 DbgHelp.
dll
,将无法识别 C++ 模式的
导出
。 主页:http://Yonsm.reg365.com 邮件:Yonsm@163.com 源码:如果需要,请访问作者主页
JNI技术手册 c/c++调用java
目录 I. 目录 1 II. java c/cpp互相调用实例(姊妹篇之一)——java调用c/cpp 4 一 先制作一个系统中有的
DLL
文件
(cpp给出的sdk接口) 4 二 JNI 7 1、 编写java
文件
7 2、
生成
.h头
文件
8 3、 用c/cpp实现这个头
文件
9 三 测试 10 四 最后补充 11 III. java c/cpp互相调用实例(姊妹篇之二)——c/cpp调用java 11 一、 编写java代码 12 二、 编译java代码 12 三、 编写 C/C++ 代码 13 四、 运行exe 18 IV. Java JNI 编程进阶 18 一、 解决性能问题 18 二、 解决本机平台接口调用问题 19 三、 嵌入式开发应用(JNI小例子) 20 1、 新增一个基础类 22 2、 定义新类继承基础类 23 3、 编写调用类 23 4、 新增两个本地方法 24 5、 修改 RunMain 类 25 6、 新增一个方法处理java对象 26 7、 新增一个方法处理数组 29 8、 改写RunMain 32 四、 参考资料: 33 V. Eclipse+CDT+MinGW 进行JAVA调用C/C++ 34 一、 安装eclipse3.2。 34 二、 安装MinGW。 34 1、 下载MinGW 34 2、 安装 34 3、 安装版本 34 4、 选择安装的编译器 34 5、 选择安装路径,下一步 35 6、 等待下载软件 35 三、 MinGW的环境变量设置 35 1、 设置Path 35 2、 设置C_INCLUDE_PATH 35 3、 设置CPLUS_INCLUDE_PATH 35 四、 做一个小技巧修改 35 五、 安装CDT插件 36 1、 下载CDT插件 36 2、 安装CDT插件 36 六、 简单介绍CDT的使用吧 36 1、 新建一个C++项目 36 2、 输入New Project名字 36 3、 给项目新建一个的源
文件
36 4、 接着出现
文件
添加的窗口,在File Name栏里面写上
文件
名 36 5、 编辑hello.cpp 37 6、 添加一个编译命令 37 七、 让我们开始进入真正的工作吧! 38 The Java side 38 1、 建立Java工程JavaHello,编写java类 38 2、 用命令
生成
头
文件
38 The C side-Compiling the Library 40 1、 建立标准C工程Cpro,并
生成
dll
文件
40 1) 将
生成
的头
文件
test_Hello.h拷贝到C工程Cpro下 40 2) 编写C类Hello.c,内容为: 40 3) 在C工程Cpro下建立hello.
def
文件
(用于定义
导出
的
函数
),内容为: 40 4) 在C工程Cpro下建立makefile
文件
,内容为: 40 5) Make Targets 40 6) Make Targets视图下双击step1,在C工程Cpro下
生成
hello.o
文件
。 41 7) Make Targets视图下双击step1,在C工程Cpro下
生成
hello.
dll
文件
。 41 2、 JAVA调用
DLL
41 1) 将hello.
dll
拷贝到Java工程JavaHello下。 41 2) 运行Hello.java,则可以看到输出结果: 41 1) 将Hello.c改为Hello.cpp 41 2) 将makefile内容改为: 41 3) 其他的几乎都不用改变也可以。 42 评论: 42 VI. c++如何调用java程序 51 DemoMain.java内容如: 51 采用vc6++ IDE,采用JNI技术实现。 51 1、 编译时 51 2、 运行时 51 程序的关键在 53 VII. JNI 53 一、 定义 53 二、 设计目的 54 三、 书写步骤 54 1) 编写java程序:这里以HelloWorld为例。 54 2) 编译 55 3)
生成
扩展名为h的头
文件
55 4) 编写本地方法实现和由javah命令
生成
的头
文件
里面声明的方法名相同的方法。 56 5)
生成
动态库 56 6) 运行程序 java HelloWorld就ok. 56 四、 调用中考虑的问题 56 1) java和c是如何互通的? 57 2) 如何将java传入的String参数转换为c的char*,然后使用? 57 3) 将c中获取的一个char*的buffer传递给java? 57 4) 不知道占用多少空间的buffer,如何传递出去呢? 58 五、 对JAVA传入数据的处理 58 1) 如果传入的是bytearray的话,作如下处理得到buffer: 58 VIII. C/C++调用JAVA类 58 一、 加载虚拟机: 59 二、 获取指定对象的类定义: 59 三、 获取要调用的方法: 59 四、 调用JAVA类方法: 60 五、 获得类属性的定义: 60 六、 数组处理: 60 七、 异常: 60 八、 多线程调用 61 Java代码 61 命令行运行:javap -s -p MyTest ,输出: 62 C代码testjava.c: 62 编译: 65 运行结果: 65
进程/线程/DLL
15,471
社区成员
49,182
社区内容
发帖
与我相关
我的任务
进程/线程/DLL
VC/MFC 进程/线程/DLL
复制链接
扫一扫
分享
社区描述
VC/MFC 进程/线程/DLL
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章