工作环境:
Windows XP + Delphi 7 
代码如下:
.....(省略)
function MyPost(Url:String;Params: TStrings): String;
begin
  Result := 'HelloWorld';
end;function ProcessDataFile(Url,FileName: Pchar): Pchar;stdcall;
var
  Report : TStrings;
begin
  Report := TStringList.Create;
  try
    Report.LoadFromFile(Strpas(filename));
    Result := Pchar(MyPost(Strpas(Url),Report));
  finally
    Report.Free;
  end;end;exports
  ProcessDataFile;beginend.问题是:
每次调用这个DLL,当文件大于3K的时候都会出现地址访问出错。Access Violation at address **** in module "MyDll.dll". Read address ****.但是相同的函数如果在主程序的空间中就不会出错(把相同的函数放在主程序中),请教各位大虾,这个是什么原因?

解决方案 »

  1.   

    问题不在这里的,主要是那个加载DLL的EXE有问题
      

  2.   

    1、不要用String作为参数  ;
    2、 使用pchar 代替 String ;
    3、如果参数有多个,可以尝试使用TStringList 玩玩;
      

  3.   

    谢谢楼上的提醒。
    String只是用在DLL内部的过程和函数,不是接口函数。
    接口函数用的就是Pchar,而现在的问题就是内部的过程函数出了问题。
      

  4.   

    另外我想说明一下,程序主要是把不同的文件数据以Post的形式发送到客户的网站上(客户就是这样设计的,很Stupid), 所以系统采用的是IdHttp.Post。 如果只是小的字符串,系统运行正常,但是我们的文件每个都在100k左右...
      

  5.   

    这个是否与主控程序的Stack Size设置有关系?另外主控程序采用的是多线程,每个线程处理不同的数据文件。
      

  6.   

    1 Result := Pchar(MyPost(Strpas(Url),Report));
     MyPost返回一个字符串,而你又把它转成了pchar这样造成了字符串的生存周期和指针的生存周期不同步,这个习惯很不好,因为字符串变量的生存周期是程序自动控制的,而pchar指针是手动控制的,容易造成访问违规
    2 尽量避免在dll做内存申请和释放,可以的话,直接把pchar在exe中申请,然后传入dll
    3 MyPost这个函数对传入的内容完全没使用,LZ故意把代码和谐了吧
      

  7.   

    谢谢10#的朋友里面的部分代码确实已经被删除了,因为问题主要在参数的传递上。
    上面的代码可以运行,但是一样会报错,楼上的朋友可以尝试一下。
    如果文件大于某个size的时候,系统就会报access violation.
      

  8.   

    上面其实已经提到过了,把解决的方法放到主控程序的代码中,不采用DLL即可解决。但是这种方式灵活性要差一些,因为以后可能还会有其他的文件格式,每次修改都需要修改主控的程序。
      

  9.   

    我在这里都说过无数遍了function foo: PChar;
    var
      x: string;
    begin
      ...
      Result := PChar(x);
    end.由于 x 是个局部变量,所以当函数结束后,x 的生存期也就结束了,rtl 会自动清理 x。因此这个函数的返回值实际上是一个野指针。但很不幸的是,当 x 是常量时,函数结束后不会销毁;当 x 不够长时(数量级不大于1M),内存管理器一般不会把它所在内存页交还给操作系统,又不会进行清0的操作,所以对它的访问一般不会直接表现出错。
    由于菜鸟实在占了绝大多数的比例,有了解到这个问题的原理的水平的人实在太少,有这个水平的人一般也不会出现这么低级的问题,所以国内论坛直接写上面代码的人比比皆是,而且这些人也没有能力写出正确的测试程序。下面是一段测试程序,能够说明为什么 Result := PChar(LocalStrVar) 为什么是非法的:program Project1;{$APPTYPE CONSOLE}uses
      FastMM4,
      SysUtils;function foo: PChar;
    begin
      Result := PChar(StringOfChar('*', 8*1024*1024));
    end;begin
      try
        Writeln(foo[1]);
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
      Readln;
    end.把“返回值”的长度改短,会发现“没有出错”。不是长度有限制,而是错了却碰巧没显现出来,当到一定长度之后才正确的出现了出错的结果。
      

  10.   

    DLL中:
    function _MyTestFunc(const AInput: PAnsiChar; AOutput: PAnsiChar): Integer;
    var
      S: String;
    begin
      S := StrPas(AInput);
      //…… 任意操作 ……
      if AOutput = nil then
        Result := Length(S)
      else
        StrPCopy(AOutput, S);
    end;
    EXE中
    function MyTestFunc(const AInput: String): String;
    var
      L: Integer;
      P: PAnsiChar;
    begin
      L := _MyTestFunc(PAnsiChar(AInput), nil);
      GetMem(P, L + 1);
      try
        FillChar(P^, L + 1, #0);
        _MyTestFunc(PAnsiChar(AInput), P);
        Result := StrPas(P);
      finally
        FreeMem(P, L + 1);
      end;
    end;
      

  11.   

    顶楼上
    function _MyTestFunc(const AInput: PAnsiChar; AOutput: PAnsiChar): Integer;
    AOutput的内存交给调用者去管理不要下面这样写,内存管理混乱
    function _MyTestFunc(const AInput: PAnsiChar): PAnsiChar;