动态调用DLL函数有时正常,有时报Access violation的异常

动态调用DLL函数有时正常,有时报Access violation的异常

typedef int (add *)(int a,int b);

void test()

{

hInst=LoadLibraryA("aimdtl.dll");

(FARPROC &)add=GetProcAddress(hInst,"add");

add(1,2);

}

按这个代码执行,add函数有时OK,有时报Access violation的异常。看到提示,第一反应就是内存异常了,但是这是什么引起了内存异常呢?

于是想着用一个变量来接收add的返回值看看。

void test()

{

hInst=LoadLibraryA("aimdtl.dll");

(FARPROC &)add=GetProcAddress(hInst,"add");

int sum=add(1,2);

}

结果,add函数执行了之后,还是有时OK,有时报Access violation的异常。这会是什么原因?于是谷歌了下,有人提到,可能要加__cdecall。于是我果断修改代码。新代码如下:

typedef int __cdecall (add *)(int a,int b);

void test()

{

hInst=LoadLibraryA("aimdtl.dll");

(FARPROC &)add=GetProcAddress(hInst,"add");

add(1,2);

}

结果,add函数执行了之后,还是有时OK,有时报Access violation的异常。纠结了!为什么 !!这时,想起在C中调用DLL函数时,需要用__stdcall,那是不是这里也要?立即改之!

typedef int __stdcall (add *)(int a,int b);

void test()

{

hInst=LoadLibraryA("aimdtl.dll");

(FARPROC &)add=GetProcAddress(hInst,"add");

add(1,2);

}

运行后,一切OK。问题至此已经解决。可这是为什么呢?于是回过头来看了看__stdcall和__cdecall的说法。

_stdcall:Win32 API的调用协议,由被调用的函数清理堆栈,所有参数自右至左入栈,生成的代码中函数名有一个_做前缀和一个@和参数的总字节数(十进制)作后缀。它不支持可变参数,但它产生的代码比_cdecl短,因为没有每次调用后的清理堆栈的代码。

_cdecl:C\C++的缺省调用协议,由调用者清理堆栈,这就是C\C++中可以使用可变参数的函数的原因,所有参数自右至作入栈,生成的代码中函数名有一个_做前缀.

至此算是明白过来了,一般dll中的函数都采用extern "C" __stdcall的方式引出函数接口的,在调用DLL中的函数时,如果没有加__stdcall和__cdecall是缺省调用了__cdecall,而__cdecall是要由调用者清理堆栈的,而在代码中并没有清理堆栈的操作,只是调用了函数,所以调

用函数的地址可能会跑飞。不跑飞就OK,而一旦跑飞就出现Access violation的异常。而_stdcall是由被调用的函数清理堆栈,所以调用函数的地址不会跑飞,自然也就OK了。

具体__stdcall/__cdecal/__fastcall的区别可以参见http://blog.csdn.net/limenglandon/article/details/8553201。

时间: 2024-12-10 07:06:44

动态调用DLL函数有时正常,有时报Access violation的异常的相关文章

C#程序实现动态调用DLL的研究(转)

摘 要:在<csdn开发高手>2004年第03期中的<化功大法——将DLL嵌入EXE>一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资源中释放出来,通过静态加载延迟实现DLL函数的动态加载,程序退出后实现临时文件的自动删除,从而为解决“DLL Hell”提供了一种解决方案.这是一个很好的设计思想,而且该作者也用C++实现了,在Internet上也有相似的VB程序,但在某一技术论坛上提起这种设计方法时,有网友提出:“这种方法好是好,但就是启动

MFC动态调用dll到指定的进程中(win7系统vs2013环境下)

一.主程序 1.新建一个MFC项目,类型选择基于对话框 2.写一个简单的窗体 点击启动事件 MessageBox(L"调用Dll到程序中成功."); 二.要调用的Dll 1.新建一个win32dll 选择dll.勾选导出符号 1.生成Dll项目 此时会在主程序Main的debug文件夹中生成了Dll.dll和Dll.lib文件 三.配置主程序Main的属性 1.选择链接器--输入--附加依赖项:Dll.lib 1.选择连接器--输入--常规--附加库目录:..\Debug 1.包含头文

C#程序实现动态调用DLL的研究

原文:C#程序实现动态调用DLL的研究 摘  要:在<csdn开发高手>2004年第03期中的<化功大法--将DLL嵌入EXE>一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资源中释放出来,通过静态加载延迟实现DLL函数的动态加载,程序退出后实现临时文件的自动删除,从而为解决"DLL Hell"提供了一种解决方案.这是一个很好的设计思想,而且该作者也用C++实现了,在Internet上也有相似的VB程序,但在某一技术论坛

C#程序实现动态调用DLL的研究[转]

摘   要: 在< csdn 开发高手> 2004 年第 03 期中的<化功大法——将 DLL 嵌入 EXE >一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资源中释放出来,通过静态加载延迟实现DLL函数的动态加载,程序退出后实现临时文件的自动删除,从而为解决“ DLL Hell ”提供了一种解决方案.这是一个很好的设计思想,而且该作者也用 C++ 实现了,在 Internet 上也有相似的 VB 程序,但在某一技术论坛上提起这种设计方法时

如何动态调用 C 函数

JSPatch 支持了动态调用 C 函数,无需在编译前桥接每个要调用的 C 函数,只需要在 JS 里调用前声明下这个函数,就可以直接调用: 我们一步步来看看怎样可以做到动态调用 C 函数. 函数地址 首先若要动态调用 C 函数,第一步就是需要通过传入一个函数名字符串找到这个函数地址,这里一个必要的前提条件就是 C 编译后的可执行文件里必须有原函数名的信息,才有可能做到通过函数名字符串找到函数地址.我们写个简单的程序来看看它编译后可执行文件的内容有没有这个信息: 编译这个文件,并用otool看下它

uVision V5.11.1.0软件仿真进不了main函数,提示*** error 65: access violation at 0x40023800 : no &#39;read&#39; permission

在百度找到一篇文章   http://www.keil.com/support/docs/814.htm 博客这篇文章           http://blog.sina.com.cn/s/blog_46d528490101qadk.html uVision V5.11.1.0软件仿真进不了main函数,提示*** error 65: access violation at 0x40023800 : no 'read' permission

动态调用dll遇到的问题

问题:动态调用第三方提供的dll报错. Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different call

?c++ 调用DLL函数,出现错误

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention. 错误原因

C# 动态调用DLL库

最近经常用到C#动态调用类库,简单的做下记录方便以后查询. 使用下面的几行代码就可以简单实现DLL类库的调用了 1 using System.Reflection; // 引入该命名空间 2 3 // 获取rocky.dll的文件路径 4 Assembly ass = Assembly.LoadFrom("./_lib/rocky.dll"); 5 // 获取该dll中命名空间RockyNameSpace中Study类 6 Type type = ass.GetType("R