array of char 和PChar的相互转换问题引起的特殊问题!(200分)

  • 主题发起人 主题发起人 tranke
  • 开始时间 开始时间
T

tranke

Unregistered / Unconfirmed
GUEST, unregistred user!
我在写一个解压缩字符串的算法,通过内存流压缩转换;比如原来的字符串长度是3500字节,压缩后是805字节,然后存放在动态数组array of char变量中,跟踪发现是二进制乱码内容;本地调用解压后是正确!

由于需要将这两个算法函数作为DLL接口,必须采用标准的DLL声明,所以需要将压缩后的数据内容array of char转换为PChar类型返回给第三方程序,现在问题是转换后PChar里面只有一个乱码值,只有1字节内容,有人说是array of char的地址,但我发现并不是,因为我另外写了一个测试程序,发现问题好像是有压缩后的乱码引起的,因为如果array of char存放的内容是正常的字符串,那么转换是成功的!

我从昨晚调试到现在都还没有成功,公司催着紧要!我将函数代码贴出来给大家看,请各位高手帮忙指点!谢谢

function GetXmlBuffer(xmlStr: PChar): PChar; stdcall;
var
nBytes, I: Integer;
tp:string;
begin
nBytes := Length(xmlStr);
GetMem(inputChar, nBytes + 1);
StrPLCopy(inputChar, xmlStr, nBytes);
inputChar[nBytes] := #0;

mStream := TMemoryStream.Create;
{将PChar转换为内存流}
mStream := PCharToMemoryStream(inputChar);

{压缩内存流}
compress(mStream);

{将压缩后的内存流写入字节流,准备Socket传输}
SetLength(vSendBuffer, mStream.Size);
mStream.Position := 0;
mStream.Read(vSendBuffer[0], mStream.Size); //mStream.Size值为805
//GetMem(Result, mStream.Size); //问题一样
Result := @vSendBuffer; //这里就可以发现Result并没有内容
end;


//外部调用

procedure TfrmZip.Button5Click(Sender: TObject);
var
pget: PChar;
begin
pget := GetXmlBuffer(PChar(Trim(Memo1.Lines.Text)));
ShowMessage(pget); //只有一个字节,是乱码
end;


补充一点,我用pointer来代替PChar也是一样的问题!
 
注意,算法本地程序运行是成功!
但是封装为DLL就出现以上的问题!
 
是这类型有问题vSendBuffer
你换成vSendBuffer:array[0..1024] of char;就没事了
///
Result := vSendBuffer;
 
较好的做法是,如果返回需要手动分配内存的类型,建议不要使用function result. 而使用procedure proc(var retvalue: PChar).

StrPCopy(retvalue, vSendBuffer)这样的语句,而不应该使用 retvalue = vSendBuffer,
这是让retvalue指针指向vSendBuffer, 而vSendBuffer的作用域是不会返回到call func中去。
 
To CoolSlob,你的意思是最后一句改为StrPCopy(retvalue, vSendBuffer)就可以吗?
 
To CoolSlob: 改为你说的方面,编译无法通过,提示string 和 dynamic array 类型不匹配
 
Result := vSendBuffer; 有问题, 跨进程怎么这样用指针呢(pchar也是指针), 你可以用共享内存解决。
 
还有!我将
mStream.Read(vSendBuffer[0], mStream.Size); //mStream.Size值为805
转换为
setlength(tmpPChar, mStream.Size);
mStream.Read(tmpPChar^, mStream.Size); //tmpPChar为PChar类型

也是一样,tmpPChar没有内容或者只有一个字节,正确的话应该是805字节
为什么呢
 
sorry,估计我写错了函数.
 
在你的 DLL 的 Uses 列表中首先加入 ShareMem:
uses
ShareMem,
SysUtils,
Classes;
 
有指针参与不用加VAR,如:
procedure proc(var retvalue: PChar);
应写成
procedure proc(retvalue: PChar);
楼主问题所在SetLength是分配内存,函数完成后,内存内容消失了.
应用vSendBuffer:array[0..1024] of char;//这种分配
 
补充:各位,下面的方法已经不采用了,我用另外的方法处理成功!

现在我改为内存映射文件处理,以下是函数代码:
pMapping: 为内存映射文件指针,已经分配了内存,请问怎样将压缩后的内存流保存在pMapping指向的映射文件上?我采用CopyMemory(pMapping, mStream.Memory, streamSize);编译正常,但是提取时候发现只有一个字节,且是乱码?
怎么回事?

function SetXmlToBuffer(var pMapping: Pointer; xmlStr: PChar): Boolean; stdcall;
var
nBytes, streamSize: Integer;
inputChar: PChar;
mStream: TMemoryStream;
vSendBuffer: array of char;
begin
nBytes := Length(xmlStr);
GetMem(inputChar, nBytes + 1);
StrPLCopy(inputChar, xmlStr, nBytes);
inputChar[nBytes] := #0;

mStream := TMemoryStream.Create;
try
{将PChar转换为内存流}
mStream := PCharToMemoryStream(inputChar);

{压缩内存流}
StreamCompress(mStream);

{将压缩后的内存流写入字节流,准备Socket传输}
streamSize := mStream.Size;

{将内存流保存为内存文件}
mStream.Position := 0;
//mStream.Memory;
//mStream.SaveToStream(TStream(pMapping));
CopyMemory(pMapping, mStream.Memory, streamSize);
//mStream.Read(PChar(pMapping)^, streamSize);
//StrCopy(PChar(pMapping), PChar(mStream.Memory));

{将字节流保存在内存文件}
//SetLength(vSendBuffer, streamSize);
//mStream.Read(vSendBuffer, streamSize);
//CopyMemory(pMapping, @vSendBuffer, mStream.Size);

Result := True;
Except
Result := False;
end;
end;
 
请各位帮忙看看,如果调试需要我偶提供完整的测试程序给你,先谢了
 
请将测试程序发到 npkaida@163.com 我帮你试试。
 
kaida,太感谢了!我已经将测试程序发给你了!请查收[:)]
 
呵呵呵呵,好人还是蛮多的嘛!
 
谢谢大家!
 
难道没有别的人有到更好的建议吗、
 
请将测试程序发到 wuhaixianghk@yahoo.com.cn 我可以帮你试试
 
应该是在函数外部分配内存,然后作为VAR参数传递进去,而不是使用返回值.
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
737
import
I
I
回复
0
查看
545
import
I
后退
顶部