主程序和DLL之间的全局变量问题(再线等!!)
多次执行TUser.create后,为什么全局变量UserName会变化。下面是代码:
主程序工程文件:
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas ' {Form1},
uUser in 'uUser.pas ';
{$R *.res}
function CurUserName: TUser;
begin
Result := UserName;
end;
procedure SetCurUserName(AUserName: TUser);
begin
UserName := AUserName;
end;
exports
CurUserName, SetCurUserName;
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
主程序窗体:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, uUser, StdCtrls, uIUser;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
objUser: IUser;
public
{ Public declarations }
end;
var
Form1: TForm1;
UserName: TUser;
implementation
function TObjUser: IUser;
external 'Project2.dll ';
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
objUser := TObjUser;
Edit1.Text := UserName.FUserName;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
objUser := nil;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
objUser := TObjUser;
Edit1.Text := UserName.FUserName;
end;
end.
Dll工程文件:
library Project2;
{ 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,
uUser in 'uUser.pas ',
uIUser in 'uIUser.pas ';
{$R *.res}
function TObjUser: IUser;
begin
result := TUser.create;
end;
exports
TObjUser;
begin
end.
TUser类:
unit uUser;
interface
uses
Windows, Forms, uIUser;
type
TUser = class(TInterfacedObject, IUser)
private
function CurUserName: TUser;
public
FUserName: string;
constructor create;
destructor Destroy;override;
end;
implementation
{ TUser }
constructor TUser.create;
var
SetCurUserName: procedure(AUserName: TUser);
begin
FUserName := 'admin ';
if CurUserName = nil then
begin
@SetCurUserName :=
GetProcAddress(GetModuleHandle(pchar(application.Exename)), 'SetCurUserName ');
SetCurUserName(Self);
end;
end;
function TUser.CurUserName: TUser;
var
GetCurUserName: function: TUser;
begin
@GetCurUserName :=
GetProcAddress(GetModuleHandle(pchar(application.Exename)), 'CurUserName ');
//if Assigned(GetCurUserName) then //找到
Result := GetCurUserName;
end;
destructor TUser.Destroy;
begin
inherited;
end;
end.
IUser接口:
unit uIUser;
interface
uses
Classes;
type
IUser = Interface(IInterface)
end;
implementation
end.
[解决办法]
尽量不使用全局变量,如必须使用全局变量则必须加前缀 'g ',同时应在变量名称中体现变量的类型。例如:
gprecUserCount: point;//名称为UserCount的全局变量,其类型为指向一结构的指针
但是在模块内部可以使用全局变量。所有模块内全局变量必须用 'F '为前缀。如果几个模块之间需要进行资料交换,则需要通过声明属性的方法来实现。例如:
type
TFormOverdraftReturn = class(TForm)
private
{ Private declarations }
FuserName: string;
FuserCount: Integer;
Procedure SetUserName(Value: string);
Function GetUserName: string;
public
{ Public declarations }
property UserName: string read GetUserName write SetUserName;
property UserCount: Integer read FuserCount write FuserCount;
end;
别处看的``我是个菜鸟 `不知道对你有帮助没