求助:VC中用结构体从DLL返回数据问题,貌似简单,极其郁闷中

bailee 2010-05-22 02:02:38
1、exe程序调用部分:
STRUCT_A recvData;
getValue(recvData);

2、DLL函数部分:
getValue(STRUCT_A & aStructFromExe)
{
aStructFromExe.iNo = 100; //此句没问题,可以赋值
aStructFromExe.strName = "test"; //此句就报错,大意是写冲突
}

3、结构体定义部分:
typedef struct _STRUCT_A_
{
int iNo;
string m_strVsersion;
}STRUCT_A, *PSTRUCT_A;

说明:程序DLL调用、运行都正常,但结构体传到DLL中后,结构体本身的指针没错,可结构体中的字符串、Map等就有问题了;

郁闷好两天了,不要告诉我用char []来代替string,因为这样可以,但不是我想要的。

编译器是VC2008,请各位帮帮忙!!! 先100分送上
...全文
578 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
sunlin7 2010-05-23
  • 打赏
  • 举报
回复
VC6.0调试成功!

把dll和exe都改成“Debug Multithreaded DLL",运行良好。

因此可以佐证是堆管理不统一的问题引起的。(关于这个,在Programming Windows via C++里面的内存管理和dll编写里面有介绍。)

还有,如果仔细研究过pe加载过程的人也知道,crt会在初始化的时候接管堆,并根据pe的配置初始化一个堆。

当我们指定pe入口,撇开crt的时候,就要小心翼翼的自己动手管理内存。
sunlin7 2010-05-23
  • 打赏
  • 举报
回复
楼主在线嘛!呵呵
楼主你把dll以MFC扩展DLL方式重新生成并将exe换成共享链接crt看看。
bailee 2010-05-23
  • 打赏
  • 举报
回复
To BloodFighter:
谢谢,我知道char[]没有问题 :)

不这么用的原因有二:
1、传回来的数据长度不固定,不想浪费内存;
2、需要传回来的数据需要用map、list等类型,如果只是string,牺牲第1条也不是太大的问题。
bailee 2010-05-23
  • 打赏
  • 举报
回复
To yincheng01:
我跟踪调试时,在EXE、DLL中,结构体的地址都是一样的,说明结构体的地址已经传到了DLL中,用到的内存也应该是EXE中的内存(我个人这么认为的,没深究过)。

但在EXE中,strName为"";(正确)
而在DLL中,strName就变为错误的地址了(错误的根源,就是strName的地址错了,你再怎么写都不行)

所以我就有点想不明白了,不信大家也试试,相信有人用过
BloodFighter 2010-05-23
  • 打赏
  • 举报
回复
接口的地方,尽量用基本类型
BloodFighter 2010-05-23
  • 打赏
  • 举报
回复
在结构体中,少用类对象,多用固定结构,特别是你这种跨模块的调用,还是顶一个TCHAR[]吧,保证没问题
bailee 2010-05-23
  • 打赏
  • 举报
回复
这么晚了CSDN上还有这么多兄弟在,看到IT技术行业真是命苦呀,想想做市场的现在可能在哪个酒吧喝酒陪客户呢(别样的辛苦) :)


To HawkOfWinter: 写在DLL中是不一样的 :)

To lisunlin0:有思想,赞一个!

但我想问题肯定不在这里,因为我看到过别人也这么用过,可我就搞不定 :)
wltg2001 2010-05-23
  • 打赏
  • 举报
回复
vs2005,我直接用上面的例子,并没报错。相反,运行正确。

难道写在dll里,不一样?
===========
string的大小是动态的,你的做法应该是在EXE中定义STRUCT_A,而在DLL中引用STRUCT_A,而在DLL中引用时,string的大小是会动态改变的,而DLL与EXE的堆并不一定相同,在动态改变大小就会出现错误。
如果仅写在EXE中,当然没有问题
zhouzhipen 2010-05-23
  • 打赏
  • 举报
回复
好像关于这个问题,在MSDN中也明确的说明。
bailee 2010-05-23
  • 打赏
  • 举报
回复
To ALL:
已经搞定了(但真正原因我还不明),谢谢各位!!!

仔细对比了一下EXE中各字段的地址与DLL中的各字段的地址,虽然在EXE与DLL中结构体的地址是一样的,但结构体中字段的地址却不一致,可能是编译选项的问题,一顿乱设,OK了!

结帖,在此除了谢谢各位走过、路过、留过言的朋友,

特别谢谢lisunlin0、zwfgdlc、yincheng01

zhouzhipen 2010-05-23
  • 打赏
  • 举报
回复
[Quote=引用楼主 bailee 的回复:]
1、exe程序调用部分:
STRUCT_A recvData;
getValue(recvData);

2、DLL函数部分:
getValue(STRUCT_A & aStructFromExe)
{
aStructFromExe.iNo = 100; //此句没问题,可以赋值
aStructFromExe.strName = "test"; //此句就……
[/Quote]


这个十有八九会出错,因为你犯了个一大禁忌!
你用string对像,在=操作时,会产生内存分配操作,但string对像会把内存指针带出DLL,并在外部对其进行释放。

而在WIN平台上,new会被转换成相应的WINAPI的操作,同时对应的delete也会被转换。所以如果是同时编译的程序,是没有什么问题的。但是DLL与主调程序不是一同编译的,所以无法确保转换的正确性。而标准库中一般是直接使用new 和delete 来管理内存的。
所以你的程序十有八九要出错的。

只要你遵循一个原则:
一个程序中所申请的内存只在该程序内释放。就不会出错了。
zwfgdlc 2010-05-23
  • 打赏
  • 举报
回复
我用VC6试了下,似乎也正常。
睡觉,明天再研究。
尹成 2010-05-22
  • 打赏
  • 举报
回复
含有指针的成员结构体内存释放:
在结构体中含有指针的成员 在给结构体分配内存时,需要通过计算这些成员变量总共占多少内存 给与分配,如果少了会出现释放出错 ,并且在赋值是需与成员变量顺序一一对应。
所以好好看看你关于这方面的内存释放问题。
中才德创 2010-05-22
  • 打赏
  • 举报
回复
#include <string>
using namespace std;

//1、exe程序调用部分:
//STRUCT_A recvData;
//getValue(recvData);

//3、结构体定义部分:
typedef struct _STRUCT_A_
{
int iNo;
string m_strVsersion;
} STRUCT_A, *PSTRUCT_A;

//2、DLL函数部分:
void getValue(STRUCT_A & aStructFromExe)
{
aStructFromExe.iNo = 100; //此句没问题,可以赋值
aStructFromExe.m_strVsersion = "test"; //此句就报错,大意是写冲突
}


int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: 在此放置代码。
STRUCT_A recvData;
getValue(recvData);


vs2005,我直接用上面的例子,并没报错。相反,运行正确。

难道写在dll里,不一样?
sunlin7 2010-05-22
  • 打赏
  • 举报
回复
dll与exe使用类实例通信的话要用MFC扩展dll机制。
从windows角度来看,不同的模块的堆是不一定相同的,也就是说exe与dll使用的堆并不是同一个,
而string和map这样的容器都会动态管理内存,假设string在exe里面的长度为1byte,现在到dll里面要扩展成5byte,那么string会先在dll里面分配空间,然后试图释放1byte的内存空间,而这个内存是在exe堆里面的,在dll里面的释放动作却是释放dll堆里面的内存,就导致了访问违列。

解决办法就是使用原始内存(静态的char数组)或者统一分配/释放(用GetProcessHeap后分配的内存并对应释放,或者用VirtualAlloc产生的内存等等,包括MFC的扩展DLL机制。)
bailee 2010-05-22
  • 打赏
  • 举报
回复
感谢大家,发帖时结构体中字义字段m_strVsersion应该是strName,各位兄弟都没有深纠,说明我的这点小错误大家还是能看明白及理解的;

其实用strcpy/format/append都是一样,还是会有问题。
因为我跟踪调试时,结构体中的string/CString/map等类型的地址都已经出错了(要么是地址错误,要么是内容很怪,我个人认为是地址已经不对了,或是指针指向的空间有误了),这就是我想不明白的地方!!!

解决不了也没问题,自己再多想想办法,

本着问题要搞清楚的原则,望各位兄弟继续,周一下班前结帖 :)
zhou1xp 2010-05-22
  • 打赏
  • 举报
回复
aStructFromExe.strName.format(test)看看
zwfgdlc 2010-05-22
  • 打赏
  • 举报
回复

又当成char了,
试下

aStructFromExe.strName = "test";


aStructFromExe.strName.append("test");
zhou1xp 2010-05-22
  • 打赏
  • 举报
回复
楼主看看VC2008是怎么重载string的=号的
zwfgdlc 2010-05-22
  • 打赏
  • 举报
回复
aStructFromExe.strName = "test"; 
换成用strcpy拷贝行不行
加载更多回复(2)

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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