DLL工程的代码:(dgull.dll)
(uses
  ShareMem,
  SysUtils,
  Classes,
  Windows;)
Function GetSystemDirectory: String;Stdcall; //得到系统目录
Var
  pcSystemDirectory: PChar;
  dwSDSize: DWORD;
Begin
  dwSDSize:=MAX_PATH+1;
  GetMem(pcSystemDirectory, dwSDSize);
  Try
    If Windows.GetSystemDirectory(pcSystemDirectory, dwSDSize)<>0 Then
      Result:=pcSystemDirectory;
  Finally
    FreeMem(pcSystemDirectory);
  End;
End;调用的代码:
Function GetSystemDirectory: String;Stdcall; external 'dgull.dll';
procedure TForm1.Button1Click(Sender: TObject);
begin
showmessage(GetSystemDirectory);
end;
*****
问题是,第一次点击Button一切正常,结果也对,可是第二次点击Button是出现错误:
存取地址***违例发生在模块"ntdll.dll"中**********
怎么解决?是不是GetSystemDirectory函数的事?

解决方案 »

  1.   

    点第三次以后错误提示就变成了存取地址***违例发生在模块"borlndmm.dll"中**********
      

  2.   

    1、DLL:library dgull;{ Important note about DLL memory management: ShareMem must be the
      first unit in your library's USES clause AND your project's (select
      Project-View Source) USES clause if your DLL exports any procedures or
      functions that pass strings as parameters or function results. This
      applies to all strings passed to and from your DLL--even those that
      are nested in records and classes. ShareMem is the interface unit to
      the BORLNDMM.DLL shared memory manager, which must be deployed along
      with your DLL. To avoid using BORLNDMM.DLL, pass string information
      using PChar or ShortString parameters. }uses
      ShareMem,
      SysUtils,
      Classes,
      Windows;Function GetSystemDirectory: PChar; Stdcall; export; //得到系统目录
    Var
      pcSystemDirectory: PChar;
      dwSDSize: DWORD;
    Begin
      dwSDSize:=MAX_PATH+1;
      GetMem(pcSystemDirectory, dwSDSize);
      Try
        If Windows.GetSystemDirectory(pcSystemDirectory, dwSDSize)<>0 Then
          Result:=pcSystemDirectory;
      Finally
        FreeMem(pcSystemDirectory);
      End;
    End;
    exports
      GetSystemDirectory index 1 name 'GetSystemDirectory' resident;begin
    end.
    ---------------------------2、EXE:...
    var
      Form1: TForm1;implementation{$R *.dfm}Function GetSystemDirectory: PChar; Stdcall; external 'dgull.dll';
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      showmessage(StrPas(GetSystemDirectory));
    end;
      

  3.   

    注意,我把DLL函数的返回值由String类型改为了PChar指针。相应的调用,及返回值转字符串StrPas的利用。
      

  4.   

    改回string类型,DLL和程序都引用ShareMem就正常了,可是关闭程序时出现Runtime error 204 at
    ****
      

  5.   

    要不,你把我的代码复制下来,新建一个DLL试试吧。完全复制。EXE的代码,我只贴出了implementation下面的部分。OK?
      

  6.   

    1.不要使用STRING,要使用PCHAR。
    2.返回值一般来说只使用定长结构,不要传递变长字符串、数组。
    3.PCHAR通过参数返回,调用前开辟足够空间,并传递空间长度给函数,函数确认空间长度,不要溢出。当空间不足,一般用布尔类型返回成功标志,或者用整型返回值通知调用者空间需求。请参考WINDOWS API函数,看看Microsoft是怎么写API函数的。
      

  7.   

    注意,我主要改动了你代码的以下位置:Dll 的  Function GetSystemDirectory: PChar; Stdcall;
                                        ~~~~~~~~EXE 的 Function GetSystemDirectory: PChar; Stdcall; external 'dgull.dll';
                                ~~~~~~~~procedure TForm1.Button1Click(Sender: TObject);
    begin
      showmessage(StrPas(GetSystemDirectory));
                  ~~~~~~~~
    end;
      

  8.   

    Try
        If Windows.GetSystemDirectory(pcSystemDirectory, dwSDSize)<>0 Then
          Result:=pcSystemDirectory;
      Finally
        FreeMem(pcSystemDirectory);//如果Result是PChar,这里释放内存是不合适的。返回的地址将会是无效的地址。
      End;
      

  9.   

    to:lihuasoft,我就是照你的复制的,乱码....
      

  10.   

    而且我是想保持string不变的,我的两个工程(dll,和应用程序)都在前面加了ShareMem,一切正常,就是退出时错误(204)
      

  11.   

    前面的代码我试验了。你再试一下下面的:library dgull;{ Important note about DLL memory management: ShareMem must be the
      first unit in your library's USES clause AND your project's (select
      Project-View Source) USES clause if your DLL exports any procedures or
      functions that pass strings as parameters or function results. This
      applies to all strings passed to and from your DLL--even those that
      are nested in records and classes. ShareMem is the interface unit to
      the BORLNDMM.DLL shared memory manager, which must be deployed along
      with your DLL. To avoid using BORLNDMM.DLL, pass string information
      using PChar or ShortString parameters. }uses
      ShareMem,
      SysUtils,
      Classes,
      Windows;Function GetSystemDirectory(var pcSystemDirectory : PChar) : boolean; Stdcall; export; //得到系统目录
    begin
      Try
        If Windows.GetSystemDirectory(pcSystemDirectory, MaxInt)<>0 Then
          Result := true;
      except
        result := false;
      end;
    end;
    exports
      GetSystemDirectory index 1 name 'GetSystemDirectory' resident;begin
    end.======================================unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}
    Function GetSystemDirectory(var pcSystemDirectory : PChar) : BOOLEAN; Stdcall; external 'dgull.dll';
    procedure TForm1.Button1Click(Sender: TObject);
    var
      P : PChar;
    begin
      GetMem(P, MAX_PATH+1);
      GetSystemDirectory(P);
      showmessage(StrPas(P));
      FreeMem(P);
    end;end.
      

  12.   

    DLL返回String类型,本身就是不可取的。因为DLL不仅仅能用在Delphi编译的程序......
      

  13.   

    Function GetSystemDirectory(var pcSystemDirectory : PChar) : boolean; Stdcall; export;
    begin
      result := False;
      Try
        If Windows.GetSystemDirectory(pcSystemDirectory, MaxInt)<>0 Then
          Result := true;
      except
        result := false;
      end;
    end;
      

  14.   

    楼上的写法不安全,应该传递字符串空间长度给函数。
    一切都要参考microsoft的格式。
      

  15.   

    改了,不行啊.
    应用程序全部代码:
    Unit Unit1;InterfaceUses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;Type
      TForm1=Class(TForm)
        Button1: TButton;
        Procedure Button1Click(Sender: TObject);
      Private
        { Private declarations }
      Public
        { Public declarations }
      End;Var
      Form1: TForm1;Implementation
    {$R *.dfm}
    Function GetSystemDirectory: String;Stdcall; external 'd.dll';
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      showmessage(GetSystemDirectory);
    end;
    End.
    **********
    DLL全部代码:
    Library d;
    Uses
      SysUtils,
      Classes,
      Windows;Function GetSystemDirectory: String;Stdcall; //得到系统目录
    Var
      pcSystemDirectory: PChar;
      dwSDSize: DWORD;
    Begin
      dwSDSize:=MAX_PATH+1;
      GetMem(pcSystemDirectory, dwSDSize);
      Try
        If Windows.GetSystemDirectory(pcSystemDirectory, dwSDSize)<>0 Then
          Result:=pcSystemDirectory;
      Finally
        FreeMem(pcSystemDirectory);
      End;
    End;
    Exports
      GetSystemDirectory;Begin
    End.
    **********
    第一次点击BUTTON一切正常,结果也没错,可是第二次点击提示什么存取地址***违例(ntdll.dll),第三次及以后就改为了d.dll(我的哪个dll)
    郁闷啊~~~怎么回事?谢了!!!!