function DataChanged(Index:Integer):Boolean;
var
DataSet:TObject;
begin
DataSet:=FStrings.Objects[Index];
//ShowMessage(DataSet.ClassName); //能正确显示 TClientDataSet
if DataSet is TClientDataSet then begin
Cds:=TClientDataSet(DataSet);
if (Cds.ChangeCount>0) or (Cds.Modified) then begin
Result:=True;
Exit;
end;
end;
Result:=False;
end;为什么这个函数放到DLL中 if DataSet is TClientDataSet then
不会真, 但是在EXE中就可以呢?开发平台是Delphi2006, XP+SP2
var
DataSet:TObject;
begin
DataSet:=FStrings.Objects[Index];
//ShowMessage(DataSet.ClassName); //能正确显示 TClientDataSet
if DataSet is TClientDataSet then begin
Cds:=TClientDataSet(DataSet);
if (Cds.ChangeCount>0) or (Cds.Modified) then begin
Result:=True;
Exit;
end;
end;
Result:=False;
end;为什么这个函数放到DLL中 if DataSet is TClientDataSet then
不会真, 但是在EXE中就可以呢?开发平台是Delphi2006, XP+SP2
解决方案 »
- Delphi 控制 CodeSoft 报错 Method 'Dialogs' not supported by automation object
- 对于高人小菜一碟~~请教高人救命!!!!!
- 怎么设置把图标放到文字的上面呢?
- 请问,如何能记录下,文件的复制信息!!!
- 是他叫着要分的,不关我的事情。我也没办法;
- 如何在EDIT文本框当前光标处插入文字
- 如何才能真正的销毁窗体呢??
- 如何控制TDBGRID的保存问题
- 怎么判断编辑框里不是汉字?
- 我是新手,请教一个打印的小问题
- 生日散分贴 之二
- 开打并关闭Form/Dll发现内存都要多占用0.0及M,重复这样的操作,长时间运行且不要出问题,寻求解决办法.
不会真, 但是在EXE中就可以呢?DataSet 是不是在主exe 传过去的?? 如果是,就好解释
完整的函数如下
function TActiveDataSet.Changed(Index:Integer):Boolean;
var
Cds:TClientDataSet;
I:Integer; function DataChanged(Index:Integer):Boolean;
var
DataSet:TObject;
begin
DataSet:=FStrings.Objects[Index];
//ShowMessage(Dataset.ClassName)
if DataSet is TClientDataSet then begin
Cds:=TClientDataSet(DataSet);
if (Cds.ChangeCount>0) or (Cds.Modified) then begin
Result:=True;
Exit;
end;
end;
Result:=False;
end;begin
Result:=False;
if Index>=FStrings.Count-1 then begin
for I:=0 to FStrings.Count-1 do
if DataChanged(I) then begin
Result:=True;
Exit;
end else begin
Result:=False;
end;
end else
Result:=DataChanged(Index);
end;//类结构如下
TActiveDataSet=Class(TComponent, IDBase, IActiveDataSet)
private
FIDBase:IDBase;
FStrings:TStringList;
protected
property DBase:IDBase read FIDBase implements IDBase;
public
//IActiveDataSet interface
function Changed(Index:Integer):Boolean;
function SetActiveDataSet(DataSet:TDataSet):Integer;
function GetActiveDataSet:TDataSet;
function GetActiveDataSets:TStrings;
procedure SaveData;overload;
procedure SaveData(DataSets:TStrings);overload; constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
end;
showMessage(DataSet.ClassName);
if DataSet is TClientDataSet then begin
测试如何??
用了CoInitialize窗体上的DataSet Action就都失效了这个问题又怎么解决?
有没有其它办法让两个本来相同的类强制类转换不出错呢 ?用ShareMem, FastMM都没有解决, 郁闷.
我的解决方案:不用is来判断,而是用一个While来判断一个类及其父类的Classname是否相同,
这个方法似乎很笨,
TActionMenu=class(TComponent, IActionMenu)
private
FActionBarItem:TActionBarItem;
public
//IActionMenu
procedure AddMenu(const Dimensions:array of Byte; Action:TAction);
procedure DeleteMenu(const Dimensions:array of Byte);
function GetActionBarItem:TActionBarItem;
function GetParentActionItem(const Dimensions:array of Byte):TActionClientItem;
procedure InsertMenu(const Dimensions:array of Byte; Action:TAction);
procedure SetActionBarItem(AActionBarItem:TActionBarItem);
property ActionBarItem:TActionBarItem read GetActionBarItem write SetActionBarItem;
public
constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
end;//GetParentActionItem不会出错, 可以正确的回转结果.
function TActionMenu.GetParentActionItem(
const Dimensions: array of Byte): TActionClientItem;
var
I:integer;
Msg:string;
ActionItem:TActionClientItem;
ActionClients:TActionClients;
begin
Result:=nil;
ActionItem:=nil;
Msg:='对不起你的第%d维值%d超标.';
ActionClients:=FActionBarItem.Items;
for I := 0 to High(Dimensions) - 1 do begin
if Dimensions[I]>ActionClients.Count then begin
Msg:=Format(Msg, [I, Dimensions[I]]);
ShowMessage(Msg);
Exit;
end else begin
ActionItem:=TActionClientItem(ActionClients.Items[Dimensions[I]]);
ActionClients:=ActionItem.ActionClients;
end;
end;
Result:=ActionItem;
end;
procedure TActionMenu.AddMenu(const Dimensions: array of Byte; Action: TAction);
var
ActionItem:TActionClientItem;
begin
ActionItem:=GetParentActionItem(Dimensions);
if ActionItem=nil then
Exit;
ActionItem:=ActionItem.Items.Add; //这里就出错. 类型不一致, 也就是说只要用到了
//ActionClientItem.Items属性都会出错, 但是奇怪能实现我的功能,但总提示错误不好.
ActionItem.Action:=Action;
end;真搞不懂是什么原因.
然后在主程序中写一个类,名字也叫做TMyClass。这个类有一个方法名叫Method2。写好后编译成exe。这下问题来了,你在主程序中使用obj = GetMyObject。这时obj的类名称是TMyClass。但是这个TMyClass并不是你在exe中定义的那个TMyClass。如果你在exe中这样写TMyClass(obj).Method2完全可以通过编译。但是被执行的代码完全有可能是Method1。这个问题的根源在于exe和dll是分开编译的。编译工具不可能有机会检查外部模块代码的类型是否匹配,因为这些代码根本就不在当前工程中。退一步来说,如果exe和dll中的TMyClass类声明完全相同,但这个相同也只是停留在语法(Syntax)的层面上,在语义(Semantic)上他们完全有可能迥异,尤其是它们的数据段不同的时候,问题将会更加突出。对于接口,因为它只有声明没有实现,所以首先它保证了语法上的一致性(当然如果你更改了接口而忘了编译所有涉及的模块,那一样会出问题)。对于采用了GUID的接口,GUID使得所有的类型都能够被唯一的识别,基本上杜绝了重名的现象(故意重用GUID的不算)。其次,接口唾弃了数据段的存在。这样一来所有对数据的访问都被限制在实现类(Implementation)的范围内。故而不会发生Class1的方法要访问Class2的数据。然后重新放在exe和dll的环境中。如果一个方法只返回一个接口(例如GetMyObject:IMyinterface),那么保存在接口的类型信息中的就只会是一系列方法的地址,而这些地址都会指向各自的实现类的方法的地址。所以你在exe中调用IMyInterface.Method1的时候就能够确定调用的是dll中的TMyClass的Method1的方法而不是别的什么模块中的同名类。说了很多废话,但愿能够对你有点帮助:)
//动态库部分
library Test;uses
Windows,
SysUtils,
Classes,
DBClient;{$R *.res}
var
FStrings:TStringList;
procedure Init;stdcall;
begin
FStrings:=TStringList.Create;
FStrings.AddObject('CDS',TClientDataSet.Create(nil));
end;
procedure Final;stdcall;
begin
if Assigned(FStrings) then
begin
FStrings.Clear;
FStrings.Free;
end;
end;
procedure TestIS;stdcall;
var
DataSet:TObject;
ClassName:String;
begin
DataSet:=FStrings.Objects[0];
ClassName:=DataSet.ClassName;
if DataSet is TClientDataSet then
MessageBox(0,PChar(ClassName),'测试',0);
end;exports
Init,Final,TestIS;
begin
end.
//以下是测试程序主窗体代码
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;implementation
procedure Init;stdcall; external 'Test.dll';
procedure Final;stdcall; external 'Test.dll';
procedure TestIS;stdcall; external 'Test.dll';
{$R *.dfm}procedure TForm1.FormCreate(Sender: TObject);
begin
Init;
end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Final;
end;procedure TForm1.Button1Click(Sender: TObject);
begin
TestIS;
end;end.