吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1762|回复: 4
收起左侧

[求助] 求助:VC调用易语言DLL问题

[复制链接]
朱朱你堕落了 发表于 2021-3-10 09:33
300吾爱币
易语言DLL如下:
1.png

VC调用

#include <string>
using namespace std;
void CaaaaDlg::OnBnClickedButton2() //这个有问题
{
        HINSTANCE hMod = LoadLibrary("testdll.dll");

        typedef string (WINAPI *pnfOrgMYFUNC)();

        pnfOrgMYFUNC CallFuntionName = (pnfOrgMYFUNC)GetProcAddress(hMod,"test");


        string s = CallFuntionName();
        MessageBox(s.c_str());

        FreeLibrary(hMod);
}

void CaaaaDlg::OnBnClickedButton3() //这个正常
{
        HINSTANCE hMod = LoadLibrary("testdll.dll");

        typedef char* (WINAPI *pnfOrgMYFUNC)();

        pnfOrgMYFUNC CallFuntionName = (pnfOrgMYFUNC)GetProcAddress(hMod,"test");

        char *s = CallFuntionName();
        MessageBox(s);

        FreeLibrary(hMod);
}

为什么使用string类似就有问题,出现异常,而使用char *就正常,最基本的原因是什么,求助各位大佬解惑。

上传下成品,可以直接看到效果。
https://52cn.lanzouj.com/iNzRkmr25ta

最佳答案

查看完整内容

[md]# 出现错误的原因 ## 代码 ```c #include "stdafx.h" #include #include using namespace std; void OnBnClickedButton2() //这个有问题 { HINSTANCE hMod = LoadLibrary("testdll.dll"); typedef string (WINAPI *pnfOrgMYFUNC)(); pnfOrgMYFUNC CallFuntionName = (pnfOrgMYFUNC)GetProcAddress(hMod,"test"); CallFuntionName(); FreeLibrary(hM ...

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

lyl610abc 发表于 2021-3-10 09:33

出现错误的原因

代码

#include "stdafx.h"
#include <windows.h>
#include <string>
using namespace std;
void OnBnClickedButton2() //这个有问题
{
        HINSTANCE hMod = LoadLibrary("testdll.dll");

        typedef string (WINAPI *pnfOrgMYFUNC)();

        pnfOrgMYFUNC CallFuntionName = (pnfOrgMYFUNC)GetProcAddress(hMod,"test");

        CallFuntionName();

        FreeLibrary(hMod);
}
int main(){
        OnBnClickedButton2();
}

运行结果

image-20210310124532091

分析结果

结果内容为:

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.

翻译内容为:

ESP的值没有通过一个函数调用被妥善保存 ,这通常是用一个调用约定调用一个函数,而用另一个调用约定调用一个函数指针的结果


这里的重点为:different calling convention,不同的调用协定

也就是说声明的pnfOrgMYFUNC并不匹配实际获取到的功能

楼主也发现将char 改为返回值的话就可以正常运行,所以归根结底问题出在string 和 char

于是问题转化为分析string 和 char*的不同

分析char* 和 string

想要了解char* 和 string 最快的办法就是分析其汇编

代码

#include "stdafx.h"
#include <string>
void function(){
        string a;
        char* b;
        a="this is a";
        b="this is b";
}

int main(){
        function();
}

反汇编代码

25:       string a;
004011BD   lea         eax,[ebp-24h]
004011C0   push        eax
004011C1   lea         ecx,[ebp-1Ch]
004011C4   call        @ILT+105(std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_str
004011C9   mov         dword ptr [ebp-4],0
26:       char* b;
27:       a="this is a";
004011D0   push        offset string "this is a" (00426040)
004011D5   lea         ecx,[ebp-1Ch]
004011D8   call        @ILT+35(std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator=)
28:       b="this is b";
004011DD   mov         dword ptr [ebp-20h],offset string "this is b" (00426034)

反汇编分析

直接看对应的赋值语句

string的赋值

27:       a="this is a";
004011D0   push        offset string "this is a" (00426040)
004011D5   lea         ecx,[ebp-1Ch]
004011D8   call        @ILT+35(std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator=)

1.首先将要赋值的字符串作为参数压入堆栈

004011D0   push        offset string "this is a" (00426040)

2.然后将ebp-1Ch的地址传给ecx

004011D5   lea         ecx,[ebp-1Ch]

ebp-1Ch的地址是什么?观察内存窗口

image-20210310130549281

image-20210310130709143

可以发现ebp-1Ch其实就是a的地址


3.调用string相关的call

004011D8   call        @ILT+35(std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator=)

char*的赋值

相比string,char*的赋值就简单多了,直接赋值即可

28:       b="this is b";
004011DD   mov         dword ptr [ebp-20h],offset string "this is b" (00426034)

出错的反汇编分析

有了前面的铺垫大致了解了string 和 char*的区别后,现在来用反汇编分析出错的原因

string反汇编

首先要明确出错的地方为调用函数处,即CallFuntionName这里,直接看反汇编:

16:           CallFuntionName();
004010AA   mov         esi,esp
004010AC   lea         ecx,[ebp-18h]
004010AF   push        ecx
004010B0   call        dword ptr [ebp-8]
004010B3   cmp         esi,esp
004010B5   call        __chkesp (00401460)
004010BA   lea         ecx,[ebp-18h]
004010BD   call        @ILT+30(std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_str
17:
18:           FreeLibrary(hMod);

看到函数里的call        __chkesp 就知道报错是这个函数引发的,也就是堆栈不平衡引起的错误

为什么使用string会引起堆栈不平衡?而使用使用char* 不会?

对比char* 反汇编

16:           CallFuntionName();
004010AA   mov         esi,esp
004010AC   call        dword ptr [ebp-8]
004010AF   cmp         esi,esp
004010B1   call        __chkesp (00401460)
17:
18:           FreeLibrary(hMod);

可以看到无论是string还是char* ,都调用了call        dword ptr [ebp-8],不同的是string还需要lea ecx和push ecx,压入string所需的参数,因而导致了后续的堆栈不平衡

总结

string和char* 的区别在于要压入参数和调用string相关的call,而char* 则是直接赋值即可,前者破坏了堆栈的平衡而引发了错误

免费评分

参与人数 2吾爱币 +1 热心值 +2 收起 理由
叫兽_william + 1 + 1 我很赞同!
朱朱你堕落了 + 1 很强大。

查看全部评分

无痕软件 发表于 2021-3-10 09:49
std::string 可以接收char* 参数直接构造对象。

如果你拿一个char* 内存直接 强转到std::string,应该会报错。

免费评分

参与人数 1热心值 +1 收起 理由
朱朱你堕落了 + 1 热心回复!

查看全部评分

Takitooru 发表于 2021-3-10 10:02
typedef string有这样写法吗??
一般都是typedef BOOL 或者  typedef char*STRING
电脑没有vc,没法测试

免费评分

参与人数 1热心值 +1 收起 理由
朱朱你堕落了 + 1 热心回复!

查看全部评分

qzhsjz 发表于 2021-3-10 11:05

易语言的 文本型const char *std::string 这种C++的STL库中的内容是C++语言独有的,不要用来和其它语言的C接口做交互。

免费评分

参与人数 1热心值 +1 收起 理由
朱朱你堕落了 + 1 热心回复!

查看全部评分

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-26 03:11

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表