今天改写一个DLL里面的string成pchar,痛苦啊!!!!!!!
于是开始研究,测试代码如下:测试环境:D6
操作系统:WIN 2000 SP4//传递pchar参数,然后返回pchar参数!!!
function TForm1.test(const str: PChar): Pchar;
var
  s:string;
begin
  s:=str;
  result:=Pchar(s+#0);
  //result:=Pchar(s);
end;//测试功能1
procedure TForm1.Button2Click(Sender: TObject);
var
  ss:string;
begin
  ss:='11100';
  E_Enc.Text:=test(Pchar(ss));//
  E_Dec.Text:=test(Pchar(ss));//
end;
procedure TForm1.Button3Click(Sender: TObject);
var
  sd:Pchar;
  ss:string;
begin
  ss:='22200';
  sd:=test(Pchar(ss));
  //ss:=sd;
  E_Enc.Text:=sd;//
  E_Dec.text:=sd;//
end;测试1:
先点击Button2,编辑框E_Enc和E_Dec都是11100。这个结果正确。
然后点击Button3,怪事就来了。E_Enc显示22200--正确,E_Dec显示1110--错误。
再点击Button3,依然奇怪,E_Enc显示22200--正确,E_Dec显示2220--错误===================
测试2:
pchar应该是一个指针,以0结尾,会不会把最后的0当成结束符号去掉了啊!我继续测试
把BUTTON2里面的SS修改为'111000',BUTTON3的SS修改为'222000'。先点击Button2,编辑框E_Enc和E_Dec都是111000。这个结果正确。
然后点击Button3,怪事就来了。E_Enc显示222000--正确,E_Dec显示111000--错误。
再点击Button3,依然奇怪,E_Enc显示222000--正确,E_Dec显示222000--正确我要抓狂了。难道奇数个字符就会错误,偶数个就不会?
还是PCHAR我没有管理好内存???于是我决定在一个函数的入口和出口的时候,
使用PCHAR,在内部处理使用STRING。继续测试
=================================测试3:
修改BUTTON3函数如下
procedure TForm1.Button3Click(Sender: TObject);
var
  sd:Pchar;
  ss:string;
begin
  ss:='22200';
  sd:=test(Pchar(ss));
  ss:=sd;
  E_Enc.Text:=ss;//
  E_Dec.text:=ss;//
end;这下E_Enc和E_Dec都显示正确了。分析测试2和测试3的不同。在于使用PCHAR和STRING上。但既然SD是PCHAR类型,应该是指针,为什么赋值
两个edit后,会有不一样呢?原因一直分析不出来。================================
求救:哪位大哥可以帮我分析PCHAR和string在使用上的不同和注意点,包括
把string类型的字符串转换为pchar作为参数传递进函数内部,并作为参数传递出来,
再转换为string有什么要注意的地方。

解决方案 »

  1.   

    测试4:
    procedure TForm1.Button3Click(Sender: TObject);
    var
      sd:Pchar;
      ss:string;
    begin
      ss:='22200';
      sd:=test(Pchar(ss));
      ss:=sd;//作一个无关痛痒的赋值
      
      E_Enc.Text:=sd;//仍然采用sd
      E_Dec.text:=sd;//仍然采用sd
    end;这下点击button2,然后点击button3,E_enc和E_Dec又都是2220--错误啊
    这下晕倒了。是不是在sd赋值给ss以后,类型转换,丢了一个0,系统认为是结尾字符,然后去掉了???继续
      

  2.   

    PChar的使用一般都是动态分配空间
    AllocMem或GetMem来使用的,这样就没任何问题http://lysoft.7u7.net
      

  3.   

    to 楼上大哥:
    我遇到的问题,该如何解决。
    看了好多帖子,都说
    string -> pchar 只要pchar(str:string)
    pchar  -> string用strpas(p:pchar);好像不行嘛。
      

  4.   

    function TForm1.test(const str: PChar): Pchar;
    var
      s:string;
    begin
      s:=str;   //s+#0导致一个临时的ansistring的分配,这个临时分配的字符串和s一样,在函数退出前被释放  result:=Pchar(s+#0);
      //result:=Pchar(s);  //所以你返回的是一个失效的指针,它的值是无定义的
    end;你可以在函数里分配一段空间共字符串存储用,但是调用者必须负责释放这段空间,如果调用者是dll,或者函数是dll的,而调用者是exe,都应该提供一个释放函数供调用者释放这个空间
      

  5.   

    procedure TForm1.Button3Click(Sender: TObject);
    var
      sd:Pchar;
      ss:string;
    begin
      ss:='22200';
      sd:=test(Pchar(ss));
      //ss:=sd;
      E_Enc.Text:=sd;//
      E_Dec.text:=sd;//
    end;测试1:
    先点击Button2,编辑框E_Enc和E_Dec都是11100。这个结果正确。
    然后点击Button3,怪事就来了。E_Enc显示22200--正确,E_Dec显示1110--错误。//樓主這裡的enc.text和dec,text均應為22200才對,因為是一個變量值。
      

  6.   

    to  alphax(英文水皮士) :
    该如何正确写呢?
    比如:DLL里面有函数
    function test(p:Pchar):pchar;在调用test的时候,exe程序里面的string该如何给test赋值,从test返回的值,又该如何转换成
    string呢?才不会有我这样的错误。
      

  7.   

    to liao5288(陈胜吴广的朋友) 
    你试过没有,不会一样的啊。不然,怎么会抓狂啊。
      

  8.   

    认真分析后,觉得应该是内存没有管理好。
    不过,实在是不解,pchar应该是一个指针,那函数的返回值用pchar,那意味着函数调用返回以后,
    返回值pchar所指的字符串s--它是一个局部变量,函数调用完毕以后,s应该就释放了,那返回值pchar怎么能指向正确的内存空间呢?下面是改进代码,在调用test函数前分配内存空间,调用后如果调用freemem释放,缺会错误。晕倒。procedure TForm1.Button2Click(Sender: TObject);
    var
      ss:string;
      sd:Pchar;
    begin
      ss:=E_Key.Text;
      GetMem(sd,1);
      sd:=pchar(ss);
      E_Enc.Text:=test(sd);//
      //FreeMem(sd);
    end;function TForm1.test(str: PChar): Pchar;
    var
      s:string;
    begin
      s:=str;
      s:=s+'d'+#0;
      result:=pchar(s);
    end;
      

  9.   

    代码改进为这样,高手帮我看看使用的正确否procedure TForm1.Button2Click(Sender: TObject);
    var
      ss:string;begin
      ss:='测试';
      E_Enc.Text:=test(@ss[1]);//end;function TForm1.test(str: PChar): Pchar;
    var
      s:string;
    begin
      s:=str;
      s:=s+'我爱老婆'+#0;
      result:=pchar(s);
    end;
      

  10.   

    爱情的种子,写段代码都不忘爱老婆,procedure FreeString(str: PChar);
    begin
      FreeMem(Str);
    end;function Test(str: PChar): PChar;
    var
      Len: Integer;
    begin
      Len := StrLen(str) + 1;
      GetMem(Result, Len);
      Move(str^, result, Len);
    end;procedure TForm1.Button2Click(Sender: TObject);
    var
      s: PChar;
    begin
      s := Test(E_Key.txt);
      E_Enc.Txt := s;
      FreeString(s);
    end;
      

  11.   

    to 楼上大哥:Len := StrLen(str) + 1;//是为了在字符串末尾加一个#0吧
    那如果处理以后,字符串变长了,那该怎么办啊。我的代码有没有问题啊。
      

  12.   

    to ghy412(用心良苦) :
    哦?什么意思啊。
      

  13.   

    就是alphax(英文水皮士)说的原因.
    这样改就不会错了. 不过有内存泄露
    function TForm1.test(const str: PChar): Pchar;
    var
      s:string;
    begin
      s:=str;
      s:=s+#0;
      result:=Pchar(s);
      Integer(s) := 0;  // 欺骗delphi内存管理器让它认为局部变量s已经被释放了
    end;
    其实是你使用pchar的方法不大对头才造成你的困惑的.
    function Test(Param: PChar): PChar;这类函数返回的PChar都不会是重新分配的内存, 要么是指向传入参数中指向的内存块中某个地址, 要么指向常量, 要么指向全局已经分配好的内存. 
    如果如你那么使用, 函数返回指向另一块动态分配的内存(而且在你的例子里这块内存还被释放掉了), 这样在释放上存在问题, 需要调用者去显式释放这块内存, 比如显式调用freemem, dispose等. 而且在通用性上有问题, 如果被别的语言写的程序调用的话肯定就会存在错误. 因为别的语言写的程序并不能释放delphi内存管理器分配的内存(它也不知道如何释放). 如果只是由delphi写的程序来调用那么根本没必要用pchar, 直接用delphi自管理的string作返回值更安全也省心.
    如果要给别的语言写的程序调用的话, 分配内存的工作必须交给调用者. 比如windows api中就有很多这样的例子, 常见的情况是函数需要调用两次, 第一次传入一个nil指针, 函数返回需要的内存大小, 由调用者分配完内存后再将具体指向内存的指针作为参数再次调用函数, 此时函数才真正将需要的数据复制入那块内存并返回一个整数数值指出具体复制了多少字节或者简单地表示调用是否成功.
      

  14.   

    樓主:問了很多個同事,沒有研究出具體的結果。
    /??pchar??,然后返回pchar??!!!
    function TForm1.test(const str: PChar): Pchar;
    var
      s:string;
    begin
      s:=str;  //字符串在此轉換時發現錯誤。
    如將:
      result:=Pchar(s+#0);//改為:result:=Pchar(str+#0),結果是正確,由此引發思考。主要還是內存沒有管理好,不過不知其真的原因
      //result:=Pchar(s);
    end;
      

  15.   

    http://www.ccrun.com/program/v.asp?id=23
      

  16.   

    如何调用pchar有什么好的方法,大侠们给个例子吧。DLL啊。DLL,写DLL的pchar好痛苦~~~~~~~
      

  17.   

    procedure TForm1.Button3Click(Sender: TObject);
    var
      ////sd:Pchar;
      ss,sd:string;
    begin
      ss:='22200';
      sd:=test(Pchar(ss));
      //ss:=sd;
      E_Enc.Text:=sd;//
      E_Dec.text:=sd;//
    end;这样就不会有错了,即在使用时先把pchar转换成String的,这样就不会每次使用时都进行转换而使结果发生变化
      

  18.   

    真是不服不行啊。嘎嘎....//传递pchar参数,然后返回pchar参数!!!
    function TForm1.test(const str: PChar): Pchar;//var
    //s:string;
    begin//s:=str;
    result:=str;//----我认为就可以搞定了。^_^
    //result:=Pchar(s);end;
      

  19.   

    楼上大哥,看到你的例子了。如果不同的开发程序如何释放DELPHI创建的内存空间?
      

  20.   

    再次改进程序,但关键是,由delphi编写的dll程序创建的内存空间,其他开发工具比如vb、vc如何释放啊。能正确释放么?=====================================
    procedure TForm1.Button2Click(Sender: TObject);
    var
      ss: string;
      p: PChar;
    begin
      ss := '测试';
      p := Test(PChar(ss));
      E_Enc.Text := p;
      SysFreeMem(p);
    end;function TForm1.Test(lpInput: PChar): PChar;
    var
      s: PChar;
      str:string;
    begin
      str:=lpInput;
      str:=str + '我爱老婆d' + PARAM_FLAG + CMD_FLAG;
      Result:=SysGetMem(Length(str));
      strpCopy(result,str);end;
      

  21.   

    Result:=SysGetMem(Length(str));修改为:Result:=SysGetMem(Length(str)+1);
      

  22.   

    //这段是你的加密dll的
    ////////////////////////-->
    procedure FreeString(str: PChar); stdcall;
      //这是释放函数
    begin
      FreeMem(Str);
    end;function Test(str: PChar): PChar; stdcall;
    var
      Len: Integer;
    begin
      Len := StrLen(str) + 1;
      GetMem(Result, Len);
      Move(str^, result, Len);
    end;
    ////////////////////////<---
    //这段是你的主程序的
    //////////////////////////-->
    procedure TForm1.Button2Click(Sender: TObject);
    var
      s: PChar;
    begin
      s := Test(E_Key.txt);
      E_Enc.Txt := s;
      FreeString(s);
    end;其他语言的情况,只要能支持stdcall调用约定就ok,释放的时候则必须调用Dll提供的释放函数
      

  23.   

    那是不是每个dll里面都必需这样成对的使用GetMem和FreeMem的定义啊。如果有多个dll程序A和B,其中A定义了FreeMem的过程B没有定义,在主程序
    是不是A和B分配的内存,都可以调用A的FreeMem进行释放啊?????????