C++调用DLL(高手请进来解答啊)

zhaoshangjun1987 2011-12-09 04:21:00
比方说我现在有个model.dll,里面有个ADD(),方法,我现在知道需要分别给他传的参数为5 和 demo。 这个2个参数,请问怎么调用这个add()方法,并且将参数传进去。不能设置函数指针,因为我的参数是要写在文件里,再读取到程序,而不是写在程序提前写好。程序里 会动态加载GetProcAddress(),获取函数指针,那怎么给这个指针传参数啊?
...全文
579 35 打赏 收藏 转发到动态 举报
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
yisikaipu 2011-12-15
  • 打赏
  • 举报
回复
因直接在release下调试,忽视了栈平衡,修改下代码

顺便说下,这里不适用于直接返回复杂对象的情况,因为入栈处理不同,所以其实仍然没有统一的方法,只不过楼主的情况可能不需要考虑这么全面

struct Para
{
int n; // 参数个数
void* arg[16];
};

void* call(void *p,Para *para)
{
int *re=0;

int n=para->n;
for(int i=0;i<n;++i)
{
void *a=para->arg[n-1-i];
_asm push a // 压地址
}

_asm
{
call p
mov re,eax
}

for(int i=0;i<n;++i)
_asm add esp,4

return re;
}

void* call_val(void *p,Para *para)
{
int *re=0;

int n=para->n;
for(int i=0;i<n;++i)
{
void *a=para->arg[n-1-i];
int x=*(int*)a; // 姑且假设都是32位整型,其它情况类似
_asm push x // 压值
}

_asm
{
call p
mov re,eax
}

for(int i=0;i<n;++i)
_asm add esp,4

return re;
}

int add(int *a,int *b)
{
return *a+*b;
}

int add_val(int a,int b)
{
return a+b;
}

char* sayhello()
{
static char s[]="hello world";
return s;
}

int _tmain(int argc, _TCHAR* argv[])
{
{
void *f=add_val; // 这里你自己去GetProcAddress,然后赋给f
int i=1,j=2;
Para para={2,{&i,&j}};
int re=(int)call_val(f,¶);
cout <<re <<endl;
}

{
void *f=add;
int i=1,j=2;
Para para={4,{&i,&j}};
int re=(int)call(f,¶);
cout <<re <<endl;
}

{
void *f=sayhello;
Para para={0};
char *re=(char*)call(f,¶);
cout <<re <<endl;
}

return 0;
}
zhaoshangjun1987 2011-12-13
  • 打赏
  • 举报
回复
[Quote=引用 32 楼 zhao4zhong1 的回复:]
引用 29 楼 zhaoshangjun1987 的回复:
引用 28 楼 wshjldaxiong 的回复:
这是我在VS2005下的试验。

C/C++ code


int fun3(int n)
{
n++;
return n;
}

int mian()
{
int i;
i = fun3(4);
}



调用反汇编是这样的。

C/C++……
[/Quote]
谢谢,确实 汇编很差,刚才自己调用成功了,呵呵 但去调用第2个就失败了,哎,因为我是这样,push参数进去,然后call调用
__asm
{
push comtrol
}
__asm
{
call addr
mov re,eax
}
不过再按照这个方法去执行第2个 就失败了,谢谢你,我确实应该好看看汇编,呵呵 不然以后调试就麻烦啦。

赵4老师 2011-12-13
  • 打赏
  • 举报
回复
[Quote=引用 29 楼 zhaoshangjun1987 的回复:]
引用 28 楼 wshjldaxiong 的回复:
这是我在VS2005下的试验。

C/C++ code


int fun3(int n)
{
n++;
return n;
}

int mian()
{
int i;
i = fun3(4);
}



调用反汇编是这样的。

C/C++ code


i = fun3(4);
004117……
额 请问参数要以什么方式PUSH进去啊!我对汇编不熟悉,因为我程序读进来都是变量类型的
[/Quote]
亡羊补牢,为时未晚。现在学汇编还来得及。

提醒:
“学习用汇编语言写程序”

“VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)”
不是一回事!
zhaoshangjun1987 2011-12-13
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 yisikaipu 的回复:]
真有必要搞这么混乱么 :)
[/Quote]

那能提供个好方法么!求教!
yisikaipu 2011-12-13
  • 打赏
  • 举报
回复
真有必要搞这么混乱么 :)
zhaoshangjun1987 2011-12-13
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 wshjldaxiong 的回复:]
这是我在VS2005下的试验。

C/C++ code


int fun3(int n)
{
n++;
return n;
}

int mian()
{
int i;
i = fun3(4);
}



调用反汇编是这样的。

C/C++ code


i = fun3(4);
0041173E pus……
[/Quote]

额 请问参数要以什么方式PUSH进去啊!我对汇编不熟悉,因为我程序读进来都是变量类型的
yisikaipu 2011-12-13
  • 打赏
  • 举报
回复
[Quote=引用 31 楼 zhaoshangjun1987 的回复:]引用 30 楼 yisikaipu 的回复:
真有必要搞这么混乱么 :)


那能提供个好方法么!求教![/Quote]

#6楼就说了,这是设计上的问题

结果你竟然允许用汇编

既然一定要这么搞,问题不是已经解决了么

struct Para
{
int n; // 参数个数
void* arg[16];
};

void* call(void *p,Para *para)
{
int *re=0;

int n=para->n;
for(int i=0;i<n;++i)
{
void *a=para->arg[n-1-i];
_asm push a // 压地址
}

_asm
{
call p
mov re,eax
}

return re;
}

void* call_val(void *p,Para *para)
{
int *re=0;

int n=para->n;
for(int i=0;i<n;++i)
{
void *a=para->arg[n-1-i];
int x=*(int*)a; // 姑且假设都是32位整型,其它情况类似
_asm push x // 压值
}

_asm
{
call p
mov re,eax
}

return re;
}

int add(int *a,int *b)
{
return *a+*b;
}

int add_val(int a,int b)
{
return a+b;
}

char* sayhello()
{
static char s[]="helloworld";
return s;
}

int _tmain(int argc, _TCHAR* argv[])
{
{
void *f=add_val; // 这里你自己去GetProcAddress,然后赋给f
int i=1,j=2;
Para para={2,{&i,&j}};
int re=(int)call_val(f,¶);
cout <<re <<endl;
}

{
void *f=add;
int i=1,j=2;
Para para={4,{&i,&j}};
int re=(int)call(f,¶);
cout <<re <<endl;
}

{
void *f=sayhello;
Para para={0};
char *re=(char*)call(f,¶);
cout <<re <<endl;
}

return 0;
}
小默 2011-12-12
  • 打赏
  • 举报
回复
这是我在VS2005下的试验。

int fun3(int n)
{
n++;
return n;
}

int mian()
{
int i;
i = fun3(4);
}


调用反汇编是这样的。

i = fun3(4);
0041173E push 4
00411740 call @ILT+515(_fun3) (411208h)
00411745 add esp,4
00411748 mov dword ptr [i],eax //返回

希望对楼主有启发。
shayla 2011-12-12
  • 打赏
  • 举报
回复
函数调用后,函数返回值会默认放到eax寄存器里。
可以放到汇编部分之前的局部变量中。
至于怎么得到,如果你对汇编不熟悉的话,可以先用c++写出来。
转成汇编看一下。
例如

33: int i = 0;
00401048 C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
34: i = MessageBox(NULL, "test", "test", MB_OK);
0040104F 8B F4 mov esi,esp
00401051 6A 00 push 0
00401053 68 1C 20 42 00 push offset string "test" (0042201c)
00401058 68 1C 20 42 00 push offset string "test" (0042201c)
0040105D 6A 00 push 0
0040105F FF 15 AC A2 42 00 call dword ptr [__imp__MessageBoxA@16 (0042a2ac)]
00401065 3B F4 cmp esi,esp
00401067 E8 34 01 00 00 call __chkesp (004011a0)
0040106C 89 45 FC mov dword ptr [ebp-4],eax


dword ptr [ebp-4]就是int i = 0在栈中的位置。
mov dword ptr [ebp-4],eax
会将返回值附给i
zhaoshangjun1987 2011-12-12
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 shayla 的回复:]
返回值在寄存器eax中
[/Quote]
DWORD dwCurrentVal = 100;
__asm{
// mov EAX,[EBX+120h];
mov dwCurrentVal,eax;

}
我是这样获取的,直接把eax给dwCurrentVal,是否正确啊,谢谢 帮忙看下!
xzj07 2011-12-12
  • 打赏
  • 举报
回复
直接从dll里导出类吧,在定义的时候把参数的默认值设置好就可以了。
zhaoshangjun1987 2011-12-12
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 shayla 的回复:]
返回值在寄存器eax中
[/Quote]
恩 我没获取到,怎么获取啊!请教了
shayla 2011-12-12
  • 打赏
  • 举报
回复
返回值在寄存器eax中
zhaoshangjun1987 2011-12-12
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 wshjldaxiong 的回复:]
引用 18 楼 wshjldaxiong 的回复:
我只知道比较蠢的办法,为那个DLL里的每一个函数都定个指针,留着,想用那个就用哪个。

我觉得这还是可行的,毕竟你从文件中读出了函数名和参数类型之后,本来就会根据信息的不同选择不同的代码来处理的后面的事情,你不妨将它们写成不同的分函数,然后以局部变量的方式定义函数指针。

我想,为每一种情况准备一个处理预案是必须的,因为我们没有办法让代……
[/Quote]

谢谢你 如果我没其他好的解决方案的,我会这样的。呵呵 我最开始也这样,但怕被老板骂!
zhaoshangjun1987 2011-12-12
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 zhao4zhong1 的回复:]
//难道楼主希望
__asm {
push 参数1
push 参数2
call 函数入口
add esp,8 //此句可能应该去掉
}
[/Quote]
刚才我这样是弄成功了,但返回值怎么取到? 在参数2里? 还是怎么回事!求赐教
hengyu654 2011-12-12
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 zhao4zhong1 的回复:]

//难道楼主希望
__asm {
push 参数1
push 参数2
call 函数入口
add esp,8 //此句可能应该去掉
}
[/Quote]

这个貌似应该是
__asm {
push 参数2
push 参数1
call 函数入口
add esp,8 //此句可能应该去掉
}
小默 2011-12-12
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 wshjldaxiong 的回复:]
我只知道比较蠢的办法,为那个DLL里的每一个函数都定个指针,留着,想用那个就用哪个。
[/Quote]
我觉得这还是可行的,毕竟你从文件中读出了函数名和参数类型之后,本来就会根据信息的不同选择不同的代码来处理的后面的事情,你不妨将它们写成不同的分函数,然后以局部变量的方式定义函数指针。

我想,为每一种情况准备一个处理预案是必须的,因为我们没有办法让代码那么智能可以自己处理。
小默 2011-12-12
  • 打赏
  • 举报
回复
我似乎看懂楼主想问什么了,他的意思似乎是说,他的程序已经跑起来了,然后去读了一个文件之后才知道他要调的是DLL里的哪个函数,所以函数指针的类型没办法在写代码的时候就定下。
我只知道比较蠢的办法,为那个DLL里的每一个函数都定个指针,留着,想用那个就用哪个。
或者用void*类型的指针?然后强行使用?不知道行不行,没试过。
shayla 2011-12-12
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 zhaoshangjun1987 的回复:]

我现在举个例子,比方说messagebox,在mode.dll中,参数都为int3个参数:1,2,3, 你要调用成功messagebox这个接口,如果换成了string 2个参数:"1","2"你也要调用成功。怎么办?大侠们,如果是让我修改函数指针的话就算了,我的本意就是不想去修改代码。做个通用的
[/Quote]

如果没有理解错楼主意思的话,可以使用汇编代码:

//先从文件得到各个需要传入的参数
参数压栈:
push param1
push param2
函数指针调用,不需要知道类型
call function
赵4老师 2011-12-12
  • 打赏
  • 举报
回复
//难道楼主希望
__asm {
push 参数1
push 参数2
call 函数入口
add esp,8 //此句可能应该去掉
}
加载更多回复(15)

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧