none
调用dll导出函数的问题 RRS feed

  • 问题

  • 动态库中的代码:

    extern "C"
    {
     __declspec(dllexport) int __stdcall add(int a,int b)

     {
      return a+b;
     }
     __declspec(dllexport) int sub(int a,int b)
     {
      return a-b;
     }

    }

    调用dll代码:

    #include<iostream>
    #include<windows.h>
    using namespace std;

    typedef int (/*__stdcall*/ * Func_1)(int ,int );
    typedef int (* Func_2)(int ,int );
    int main()
    {
     HINSTANCE hinsdll;
     hinsdll=LoadLibrary(L"Text.dll");
     if(hinsdll==NULL)
     {
      FreeLibrary(hinsdll);
      exit(0);
     }
     Func_1 add;
     Func_2 sub;
     add=(Func_1)GetProcAddress(hinsdll,"_add@8");
     sub=(Func_2)GetProcAddress(hinsdll,"sub");
     if(add==NULL)
     {
      cout<<"获取函数add地址失败!"<<endl;

    FreeLibrary(hinsdll);
      exit(0);
     }
     if(sub==NULL)
     {
      cout<<"获取函数sub地址失败!"<<endl;

    FreeLibrary(hinsdll);
      exit(0);
     }
     cout<<add(5,9)<<endl;//在调用的时候出错,Why?
     cout<<sub(6,9)<<endl;
     return 1;
    }

    这是为什么呢?能够获取函数地址,但是调用出错......

     

    2008年12月7日 4:08

答案

  • 在服务端,也就是DLL中,add函数使用__stdcall方式。而客户端的函数指针使用的是C++默认的方式__cdecl。两种方式在调用时是有区别的。所以会出错。

    __cdecl是C/C++和MFC程序默认使用的调用约定,也可以在函数声明时加上__cdecl关键字来手工指定。采用__cdecl约定时,函数参数按照从右到左的顺序入栈,并且由调用函数者把参数弹出栈以清理堆栈。因此,实现可变参数的函数只能使用该调用约定。由于每一个使用__cdecl约定的函数都要包含清理堆栈的代码,所以产生的可执行文件大小会比较大。__cdecl可以写成_cdecl。
    __stdcall调用约定用于调用Win32 API函数。采用__stdcall约定时,函数参数按照从右到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,函数参数个数固定。由于函数体本身知道传进来的参数个数,因此被调用的函数可以在返回前用一条ret n指令直接清理传递参数的堆栈。__stdcall可以写成_stdcall。



     

    2008年12月8日 2:02
    版主