首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ Builder >

CB 调用 VC 的DLL 疏失

2013-03-12 
CB 调用 VC 的DLL 出错接口头文件#include stringtypedef unsigned int uintstruct IMpkManip{virtual

CB 调用 VC 的DLL 出错
接口头文件  


#include <string>

typedef unsigned int uint;


struct IMpkManip
{
virtual void release() = 0;
virtual bool addFile(const char* sourceFilename,const char* targetFilename,bool replaceExist = true,bool compress = true,bool encrypt =false) = 0;

};

extern "C" __declspec(dllexport)  IMpkManip* createMpkManip();



然后我在 VC 里面调用这个DLL 正常


#include "IMpkManip.h"
#include <windows.h>
#include <stdlib.h>

using namespace std;
int main()
{
HMODULE pDll = LoadLibrary("Base.dll");
typedef IMpkManip* (*CREATEMPKMANIP)();
CREATEMPKMANIP pShowDlg = (CREATEMPKMANIP)GetProcAddress(pDll,"createMpkManip");
IMpkManip* wwManip = pShowDlg();
wwManip->addFile("c:\\1.txt","1.txt",true,true,false);
system("pause");
return 0;
}



在 C++Builder 里面调用就不正常.


#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include "IMpkManip.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
HMODULE pDll = LoadLibrary("Base.dll");
typedef IMpkManip*  (*CREATEMPKMANIP)();
CREATEMPKMANIP pShowDlg = (CREATEMPKMANIP)GetProcAddress(pDll,"createMpkManip");
IMpkManip* wwManip = pShowDlg();
wwManip->addFile("c:\\1.txt","1.txt",true,true,false);
system("pause");
return 0;
}



为什么啊??
[解决办法]
两个问题:
1. 在 dll 和 exe 中都应该指定调入方式,如 WINAPI (也就是__stdcall)
extern "C" __declspec(dllexport)  IMpkManip* __stdcall createMpkManip();

2. 一般不要跨开发工具导出类指针,而是导出标准函数,如 int, unsigned char 等
[解决办法]
调用约定:
    __cdecl 缺省
      是 Borland C++ 的缺省的 C 格式命名约定,它在标识符前加一下划线,以保留
    它原来所有的全程标识符。参数按最右边参数优先的原则传递给栈,然后清栈。
        extaern "C" bool __cdecl TestFunction();
      在 def 文件中显示为 
        TestFunction@1
      注释: @1 表示函数的顺序数,将在“使用别名”时使用。

    __pascal Pascal格式
      这时函数名全部变成大写,第一个参数先压栈,然后清栈。
        TESTFUNCTION@1//def file

    __stdcall 标准调用
      最后一个参数先压栈,然后清栈。
        TestFunction@1//def file

    __fastcall 把参数传递给寄存器
      第一个参数先压栈,然后清栈。
        @TestFunction@1//def file
[解决办法]
CB有时就出这样的问题,不行就再用一个DLL封装一下
[解决办法]
引用:

引用:CB有时就出这样的问题,不行就再用一个DLL封装一下

这个方法可以.  不过已经是下下策了..   有没有更好的解决办法啊?

我也碰到过几次这样的事情,都是自己用VC再做个DLL重新封装,也不是很麻烦,如果原DLL的输出函数很多很复杂的话,可以把一部分业务逻辑也封装进去,简化调用接口;如果简单的话,就直接封装成个warpper就行了
[解决办法]
引用:
输出函数略多了些.  我在汇编里面看C++Builder 多压了一个参数进去.  不知道他为什么要这么做.

VC 里面是 push5次   CB  push5次以后  又push 了一次 eax

这个好像是控制不了的,可能与COFF转OMF的过程有关,所以现在我已经打算放弃CB了,还是用VC省心
[解决办法]
参考下我这里的,
http://blog.csdn.net/zhouzhangkui/article/details/5815797

你的问题 可能主要出在 _declspec(dllexport) 、__stdcall 等约定上
仔细检查下
[解决办法]
引用
输出函数略多了些.  我在汇编里面看C++Builder 多压了一个参数进去.  不知道他为什么要这么做.

VC 里面是 push5次   CB  push5次以后  又push 了一次 eax 


俺也好奇,它返回前调用了 [[eax]+$28],跟踪看看这个eax是啥对象,到底干了啥
[解决办法]
引用:
引用:输出函数略多了些.  我在汇编里面看C++Builder 多压了一个参数进去.  不知道他为什么要这么做.

VC 里面是 push5次   CB  push5次以后  又push 了一次 eax
这个好像是控制不了的,可能与COFF转OMF的过程有关,所以现在我已经打算放弃CB了,还是用VC省心


首先确定调用约定,VC demo里是this call,this指针通过ecx传递,其他参数通过堆栈由右向左传递,函数返回时,由被调用函数负责恢复堆栈;CB demo里是__cdecl,所有参数通过堆栈由右向左传递,函数返回时,由调用函数负责恢复堆栈。

这就能解释为什么你看到VC里push 5次,CB里push 6次(最后一次push eax是传递IMpkManip this指针)。

[解决办法]
总之,不要这么玩。
[解决办法]
引用:
在 OllyDbg 里面下断点后发现

VC 调用的参数是正常的

C++Builder 调用的 ("c:\\1.txt")  变成了第二个参数

// 是调用约定的问题吗?  应该都是 cdecl才对啊?


不管VC还是CB,他们都是第二个参数,第一个是this。
[解决办法]
跨编译器dll,不要使用类、虚函数。如果你非要这么做,可以做成com。

不同编译器,类成员的内存布局是不同的,虚函数table实现也不一样。

一般,dll尽可能只使用基本类型作为参数。
[解决办法]
补充,不同编译器类成员内存布局可能是不同的。

热点排行