社区
进程/线程/DLL
帖子详情
我用MFC做了一个DLL为什么调用的时候,系统报 无法起动DLL
lx_neteasy
2003-10-20 11:54:18
我用MFC做了一个DLL为什么调用的时候,系统报 无法起动DLL
...全文
48
7
打赏
收藏
我用MFC做了一个DLL为什么调用的时候,系统报 无法起动DLL
我用MFC做了一个DLL为什么调用的时候,系统报 无法起动DLL
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
7 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
wdllove
2003-10-21
打赏
举报
回复
你传往dll里传参数了吗?
seacode
2003-10-21
打赏
举报
回复
你說的“無法啓動”是啓動失敗呢?還是找不到dll,是否有詳細的出錯信息?
lx_neteasy
2003-10-20
打赏
举报
回复
我已经在注册表里 注册了阿
larryvc
2003-10-20
打赏
举报
回复
你的DLL注册了吗?在运行下试试regsvr32 "your dll name"
lx_neteasy
2003-10-20
打赏
举报
回复
可能是什么原因
lx_neteasy
2003-10-20
打赏
举报
回复
我为ms _OFFICE
写了一个读取其他格式文档的DLL 好像是WORD 调用DLL时 说该DLL
无法起动
meishi
2003-10-20
打赏
举报
回复
请你说明白,是编译出错,还是连接时出错,或者运行时出错,是主程序(调用库的程序)还是库出错,你能把具体出错的的情形具体描述一下吗,你的主程序开发工具是什么?
MFC
DLL
全局HOOK魔兽改建精灵
MFC
DLL
全局HOOK魔兽改建精灵 只能对魔兽起效果
VC内存泄露误
报
演示程序
使用vc开发
mfc
程序时,在
调用
了win32
dll
(即不使用
mfc
的
dll
)时,
mfc
90.
dll
后于win32
dll
加载,在退出程序时
mfc
90.
dll
先释放,这时它会将win32
dll
中的全局变量,函数static变量视为内存泄露,而实际上随后win32
dll
卸载时会正常释放,导致内存泄露误
报
。 本程序演示了win32
dll
中的std::string的全局变量和函数内static变量的内存泄露误
报
用法:编译好后,
起动
程序点击下button,然后退出程序,观察output窗口的输出
MFC
快速入门
以C++类的形式封装了Windows API,并且包含
一个
应用程序框架,以减少应用程序开发人员的工作量,这是一套
mfc
快速入门的课程,主要对
MFC
各个控件的讲解如何使用,以及Windows
MFC
框架原理与工程应用开发。本课程重点...
自己写的
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; typedef 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)(此关键字对于类和函数而言并非必须,但对于变量而言则是必须的)。所以通常我们会定义
一个
宏来包装之,比如 #ifdef MY
DLL
_EXPORTS # define MY
DLL
_API __declspec(
dll
export) #else # define 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,此文件定义出 #ifdef TEST_EXPORTS # define TEST_API __declspec(
dll
export) #else # define 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中) : #ifdef __cplusplus #define EXTERN_C extern "C" #else #define 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 头文件段 #ifdef __cplusplus extern "C" { #endif 函数和变量声明 ... #ifdef __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
不包括变量的定义 #ifdef TEST_EXPORTS # define TEST_API __declspec(
dll
export) #else # define TEST_API #endif 然 后只要把工程的配置属性(Configuration Type)简单地在Static Library (.lib)或者Dynamic Library (.
dll
)切换即可(VC会自动地为
DLL
添加预处理器TEST_EXPORTS,为静态库取消TEST_EXPORTS)。 2.
DLL
包含变量定义,也是标准的
做
法 #ifdef TEST_BUILD_AS_
DLL
#ifdef TEST_EXPORTS # define TEST_API __declspec(
dll
export) #else # define TEST_API __declspec(
dll
import) #endif #else #define TEST_API #endif 如果要将库
做
成
DLL
,那么需要
DLL
创建者添加预处理器TEST_BUILD_AS_
DLL
和TEST_EXPORTS,后者通常由编译器自动添加;如果
做
成静态库则不需要添加任何预处理器。 用户则可以通过添加或取消TEST_BUILD_AS_
DLL
来使用动态库或静态库。 对于
DLL
的用户,TEST_BUILD_AS_
DLL
这个名称似乎起得不好。下面的
做
法或许会更合理些: #if defined(TEST_API) #error "macro alreday defined!" #endif #if defined(TEST_BUILD_
DLL
) && defined(TEST_USE_
DLL
) #error "macro conflict!" #endif #if defined(TEST_BUILD_
DLL
) // build
dll
# define TEST_API __declspec(
dll
export) #elif defined(TEST_USE_
DLL
) // use
dll
# define TEST_API __declspec(
dll
import) #else // build or use library, no preprocessor needs # define TEST_API #endif 相关链接 微软
DLL
专题 Windows API编程之动态链接库(
DLL
)
VC
MFC
编程方法笔记
Visual C++
MFC
编程方法笔记 窗口/描画 非模态对话框的生成方法 对话栏的实现方法 矩形区域定位 SetWindowExt与SetViewportExt SetWindowOrgとSetViewportOrg 椭圆形窗口 为控件显示工具提示信息 对话框的背景色与背景图 Splash窗口 防止描画時画面闪烁 表现颜色(VC++) 打印 使用打印机 打印坐标紙 程序控制 资源文件国际化 直接从
DLL
调用
函数 防止应用程序重复
起动
CException类的派生与使用 实现VB的DoEvents函数 用CWinThread派生类创建带有窗口的线程 数据交换 使用剪贴板(VC++) 通讯与网络 串行通信(簡易版) 命名管道通讯(簡易版) 部品/控件 文件选择框CFileDialog的个性化 列举可以使用的字模名 自描画按钮 自描画列表框 自描画下拉组合框 自描画列表控件与列表VIEW 在
MFC
中实现平面滚动条 菜单的自描画 算法 坐标旋转 快速傅氏变换 拉格朗日插值法 牛顿插值法 计算圆周率 河内塔(動画) 递归曲线 递归曲线C-曲线 描画曼德布洛特集合 文件/目录操作 文件查找,文件属性 文件的复制,移动,删除,更名 遍历文件目录 文件目录操作
进程/线程/DLL
15,471
社区成员
49,182
社区内容
发帖
与我相关
我的任务
进程/线程/DLL
VC/MFC 进程/线程/DLL
复制链接
扫一扫
分享
社区描述
VC/MFC 进程/线程/DLL
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章