Delphi 检测是否有人在使用我的TADOConnection后使用它';他被释放了?

Delphi 检测是否有人在使用我的TADOConnection后使用它';他被释放了?,delphi,ado,delphi-5,Delphi,Ado,Delphi 5,今天,一位同事来找我,发现在Windows XP上运行但在Windows 7上失败的代码出现错误: 用户登录“SalesOrdersystem”失败 我的phychic调试告诉我,他正在对一个已关闭的数据库连接运行一个查询,或者他忘记打开了 从ADO2.6开始,在Windows Vista中,连接字符串中的PersistSecurityInfo的默认值是False,而不是True Windows Vista之前的连接字符串,例如: Data Source=deathstar;User ID=Sa

今天,一位同事来找我,发现在Windows XP上运行但在Windows 7上失败的代码出现错误:

用户登录“SalesOrdersystem”失败

我的phychic调试告诉我,他正在对一个已关闭的数据库连接运行一个查询,或者他忘记打开了

从ADO2.6开始,在Windows Vista中,连接字符串中的
PersistSecurityInfo
的默认值是
False
,而不是
True

Windows Vista之前的连接字符串,例如:

Data Source=deathstar;User ID=SalesOrderSystem;Password=password1
将在连接打开后将密码保留在连接字符串中,这相当于:

Data Source=deathstar;User ID=SalesOrderSystem;
      Password=password1;PersistSecurityInfo=true
从Windows Vista开始,默认情况下,密码将从连接的
ConnectionString
属性中删除:

Data Source=deathstar;User ID=SalesOrderSystem
这相当于

Data Source=deathstar;User ID=SalesOrderSystem;
      Password=password1;PersistSecurityInfo=false
我知道我的同事正在经历密码被删除的行为。然后,当连接关闭时,他试图打开一个查询(即ADOQuery.open),该查询会错误地尝试打开连接。但是,如果没有在连接字符串中保存密码,则会出现原始错误

问题变成了,“为什么不先打开连接就使用连接?”

我们将其追溯到(多线程代码),他使用的连接后来被释放:

伪代码:

而不是

customer := TCustomer.Create(DataModule.ADOConnection);
customer.RefreshFromDatabase;
开玩笑的是,我建议他可以通过将连接字符串更改为包含
persistentsecurityinfo=True
,来掩盖错误并保留潜在的崩溃:

connectionString := ...+
    ';PersistSecurityInfo=True';
他做到了


我们有一些库代码在内部使用
ADOConnection
对象。我希望能够从以下位置更改我的代码:

destructor TAsyncFill.Destroy; 
begin
   ...
   FreeAndNil(FADOConnection)
end;

但我相信它会引入错误,在过去的工作中经常发生的事情

我想到的是某种闭包,在这里我可以向连接对象注入
OnConnect
处理程序:

destructor Destroy; 
begin
   ...
   FADOConnection.Close;
   FADOConnection.BeforeConnect := { 
       OutputDebugString('You''re using a connection that''s been freed!'); 
       Windows.Beep(1000, 60000) };
   FreeAndNil(FADOConnection);
end;
但是Delphi没有匿名事件处理程序

有人能想出一种方法来提醒人们在对象被释放后使用它吗



注意:我知道没有人支持我的要求。-考虑到现实的局限性。

具有完全调试功能的FastMM将在代码释放对象后访问对象时通知您


显然,您不能在启用该设置的情况下发布,但在运行测试套件时将其打开,这样的错误将被清除到公开的视野中。

FastMM with full debug将在代码释放对象后访问对象时通知您


显然,您不能在启用该设置的情况下发布,但在运行测试套件时将其打开,这样的错误将被清除到可见的位置。

为什么编码器使用可能已释放的TADOConnection对象?为什么不让线程创建自己的连接?这将允许线程控制连接的生命周期。

为什么编码器使用可能已释放的TADOConnection对象?为什么不让线程创建自己的连接?这将允许线程控制连接的生命周期。

由于您正在“免费”和“无”AdoConnection,我假设您自己也在实例化它。在这种情况下,您可以派生自己的TMyAdoConnection并实例化它。如果采用“拦截器”方法,甚至不必给它另一个类名:

type
  TAdoConnection = class(AdoDb.TAdoConnection)
  end;
然后,重写受保护的DoConnect方法。尽管名称不同,它并不仅仅是一个触发OnConnect事件的方法。它实际上打开了一个连接。还有一种类似的DoDisconnect方法,它实际上关闭了连接

在这两个被重写的方法中,加上Create和Destroy的重写,您可以编写一个简单的检测机制,用于检测何时打开和关闭与Creates和Destroy不匹配

如果您有一个AdoConnection实例,您可以在几个全局变量中跟踪情况。否则,您可能必须编写一个小的注册表,以便跟踪每个实例的内容。如果实例已被释放并设置为nil,那么尝试在注册表中查找“Self”会很困难。因此,您可能必须暂时放弃FreeAndNil,并重新编码任何
(如果已分配)(FAdoConnection)
,以检测是否仍需要创建实例以及其他内容

警告:这是基于Delphi 6中的TAdoConnection。我目前没有在Delphi5中安装Ado组件。因此,您必须检查D5中的DoConnect和DoDiscoonect是否存在并且是虚拟的。

由于您的adoconnect是“FreeAndNil”,我假设您自己也在实例化它。在这种情况下,您可以派生自己的TMyAdoConnection并实例化它。如果采用“拦截器”方法,甚至不必给它另一个类名:

type
  TAdoConnection = class(AdoDb.TAdoConnection)
  end;
然后,重写受保护的DoConnect方法。尽管名称不同,它并不仅仅是一个触发OnConnect事件的方法。它实际上打开了一个连接。还有一种类似的DoDisconnect方法,它实际上关闭了连接

在这两个被重写的方法中,加上Create和Destroy的重写,您可以编写一个简单的检测机制,用于检测何时打开和关闭与Creates和Destroy不匹配

如果您有一个AdoConnection实例,您可以在几个全局变量中跟踪情况。否则,您可能必须编写一个小的注册表,以便跟踪每个实例的内容。如果实例已被释放并设置为nil,那么尝试在注册表中查找“Self”会很困难。因此,您可能必须暂时放弃FreeAndNil,并重新编码任何
(如果已分配)(FAdoConnection)
,以检测是否仍需要创建实例,wi
type
  TAdoConnection = class(AdoDb.TAdoConnection)
  end;