0

今日、同僚が、Windows XP では機能するが Windows 7 では機能しないコードのエラーを報告してくれました。

ユーザーが「SalesOrdersystem」にログインできませんでした

私の物理的なデバッグは、閉じられたデータベース接続に対してクエリを実行していたか、開くのを忘れていたことを教えてくれました。

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(ADOConnection)
ADOConnection.Free;
customer.RefreshFromDatabase;

それよりも

customer := TCustomer.Create(DataModule.ADOConnection);
customer.RefreshFromDatabase;

冗談で、接続文字列を次のように変更することで、エラーをマスクし、クラッシュの可能性を残すことができると提案しましたPersistSecurityInfo=True

connectionString := ...+
    ';PersistSecurityInfo=True';

彼がしたこと。


内部でオブジェクトを使用するライブラリ コードがいくつかありADOConnectionます。コードを次から変更できるようにしたいと思います。

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

destructor TAsyncFill.Destroy; 
begin
   ...
   FADOConnection.Close;
   FADOConnection.ConnectionString := 'This connection object has been freed. Why are you using it?';
   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 には匿名のイベント ハンドラがありません。

オブジェクトが解放された後、オブジェクトを使用しているときに人々に警告できる方法を考えられる人はいますか?


注:私が求めていることに対するサポートがないことを理解しています。現実の限界を考慮して、可能な限り最高のハックのアイデアを求めています。

4

3 に答える 3

2

AdoConnection を "FreeAndNil" にしているので、自分でもインスタンス化していると思います。その場合、独自の TMyAdoConnection を派生させてインスタンス化することができます。「インターセプター」アプローチを使用する場合は、別のクラス名を付ける必要さえありません。

type
  TAdoConnection = class(AdoDb.TAdoConnection)
  end;

次に、保護された DoConnect メソッドをオーバーライドします。その名前にもかかわらず、OnConnect イベントをトリガーする「単なる」メソッドではありません。実際に接続を開きます。実際に接続を閉じる同様の DoDisconnect メソッドもあります。

これら 2 つのオーバーライドされたメソッドに加えて、Create と Destroy のオーバーライドを使用して、Opens と Closes が Creates と Destroys と一致しない場合の単純な検出メカニズムを作成できます。

単一の AdoConnection インスタンスがある場合は、いくつかのグローバル変数で物事を追跡できます。それ以外の場合は、各インスタンスの情報を追跡する小さなレジストリを作成する必要がある場合があります。インスタンスが解放されてnilに設定されている場合、そのレジストリで「Self」を見つけようとしても難しいでしょう。したがって、当分の間 FreeAndNil を放棄しif Assigned(FAdoConnection)、インスタンスを作成する必要があることを検出するために何かを再コーディングする必要があるかもしれません。

警告: これは Delphi 6 の TAdoConnection に基づいています。現時点では Delphi 5 に Ado コンポーネントがインストールされていません。したがって、DoConnect と DoDiscoonect が存在し、D5 にも仮想であることを確認する必要があります。

于 2011-08-26T17:48:18.093 に答える
1

完全なデバッグを備えた FastMM は、オブジェクトが解放された後にコードがオブジェクトにアクセスすると通知します。

ここに画像の説明を入力

明らかに、その設定をオンにして出荷することはできませんが、テスト スイートを実行するときにオンにすると、そのようなバグが公開されます。

于 2011-08-26T16:40:08.037 に答える
0

すでに解放されている可能性のある TADOConnection オブジェクトをコーダーが使用しているのはなぜですか? スレッドに独自の接続を作成させないのはなぜですか? これにより、スレッドは接続のライフサイクルを制御できます。

于 2011-08-26T16:46:36.403 に答える