社区
进程/线程/DLL
帖子详情
那种导出类,函数和变量的DLL是否可以用loadlibrary显示调用?如何调用
bjxiaoye
2005-09-03 10:12:54
那种导出类,函数和变量的DLL是否可以用loadlibrary显示调用?如何调用
...全文
218
13
打赏
收藏
那种导出类,函数和变量的DLL是否可以用loadlibrary显示调用?如何调用
那种导出类,函数和变量的DLL是否可以用loadlibrary显示调用?如何调用
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
13 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
bjxiaoye
2005-10-04
打赏
举报
回复
请问 Anikan(皮皮鱼) 。能否详细说说呢、
kenyle
2005-09-24
打赏
举报
回复
我也有遇到过这样的问题,问题就出在MethodAddress是个什么东西呢?
例如:
class __declspec(dllexport) myClass
{
public:
myClass().....
void display();
}
如果我要用到display 那么MethodAddress 是myClass::display还是myClass.display还是...
Anikan
2005-09-23
打赏
举报
回复
不能这样做的。要实现也可以,参照COM思想就可以了。
hqulyc
2005-09-23
打赏
举报
回复
导出类的dll不能被动态加载--------
其实类只是数据和代码的一个封装
如果你一定要动态加载的话
得到的就是数据和一个个的函数
这样的话类的概念就不存在了
bjxiaoye
2005-09-13
打赏
举报
回复
不对啊,可是你在哪体现“类”呢?我试了,还是不行
hqulyc
2005-09-12
打赏
举报
回复
是这个GetProcAddress...
写错了
bjxiaoye
2005-09-09
打赏
举报
回复
请问GetProcess是否是GetProcAddress,为什么我测试了不行呢
bjxiaoye
2005-09-09
打赏
举报
回复
哦,知道了
bjxiaoye
2005-09-09
打赏
举报
回复
请问 lpRegHnd 是什么,是一个MACRO定义吗?如何定义呢
hqulyc
2005-09-09
打赏
举报
回复
MethodAddress -->MethodName
hqulyc
2005-09-09
打赏
举报
回复
HINSTANCE hDLL = ::LoadLibrary("dllPath");
typedef BOOL (_stdcall *lpRegHnd)(void);
lpRegHnd regHND;
regHND = (lpRegHnd)::GetProcess( hDLL, "MethodAddress");
if (regHND == NULL )
{
return -1;
}
regHND(); //Call Method;
::FreeLibrary( hDLL );
bjxiaoye
2005-09-05
打赏
举报
回复
能详细说说吗
jerry
2005-09-03
打赏
举报
回复
显式调用很麻烦
自己写的
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
函数
Load
Library
或者MFC提供的Afx
Load
Library
将
DLL
加载到内存,再用GetProcAddress()在 内存中获取引入
函数
地址,然后你就可以象使用本地
函数
一样来
调用
此引入
函数
了。在应用程序退出之前,应该用Free
Library
或MFC提供的 Afx
Load
Library
释放
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
=
Load
Library
(
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; } Free
Library
( 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)加载,必须由用户使用
Load
Library
和Free
Library
来控制
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
)
Python
调用
C语言程序方法解析
首先我们需要将编写好的c程序文件编译为动态库文件(后缀名为.so) 使用下面的命令: gcc 原文件名.c -shared -o 新文件名.so 然后在python程序中导入模块:from ctypes import * 在python中引入c动态库,并定义一个
变量
用来接收动态库: a=c
dll
.
Load
Library
(“动态库文件路径”) 然后就可以
调用
其中的
函数
了。 a.
函数
名() 具体使用示例如下: //c语言代码 #include
void fun() { printf("hello world\n"); } #python代码 from ctypes
Python
DLL
变量
:如何使用Python
调用
DLL
函数
?
当需要在Python中
调用
其他语言编写的动态链接库(
DLL
)
函数
时,我们可以使用ctypes模块来实现。在本文中,我们将介绍如何使用Python ctypes模块
调用
DLL
函数
,以及如何在Python中处理从
DLL
返回的数据。需要注意的是,在 Windows 64位 环境下,由于Python默认为32位,因此需要加载64位的
DLL
文件。通过了解
函数
的参数和返回
类
型,以及使用结构体和指针
类
型来处理复杂数据,我们可以轻松地在Python中
调用
其他语言编写的
DLL
函数
。
DLL
的概念、分
类
、
调用
,
DLL
如何
导出
函数
、
变量
和
类
1、
DLL
的概念
DLL
(Dynamic Linkable
Library
),动态链接库,可以向程序提供一些
函数
、
变量
或
类
。这些可以直接拿来使用。 静态链接库与动态链接库的区别: (1)静态链接库与动态链接库都是共享代码的方式。静态链接库把最后的指令都包含在最终生成的EXE文件中了;动态链接库不必被包含在最终EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个
c++
调用
dll
函数
,
导出
类
中的成员
函数
********注意写好
dll
后 用depends查看
导出
函数
时会发现
导出
的
函数
名不是你写的那样出现所谓的乱码入?等*************这就注定
dll
不能通过
显示
连接的方式导入。 如果想通过
显示
连接的方式导入可以为
类
添加一个友元
函数
去实现
显示
连接创建
类
得对象************************************** 这里对于
导出
类
,我们使用隐式链接;直接看代码;
进程/线程/DLL
15,471
社区成员
49,182
社区内容
发帖
与我相关
我的任务
进程/线程/DLL
VC/MFC 进程/线程/DLL
复制链接
扫一扫
分享
社区描述
VC/MFC 进程/线程/DLL
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章