2

使用中のファイルを削除できるように、ロックを解除または削除するにはどうすればよいですか? 問題のファイルは、私自身のアプリケーションで使用されています。

具体的には、私のアプリケーションはフリーウェアの Zeos Lib を使用しています。データベースを開いて保存するとき、sqlite3.dll ファイルはアプリケーションと同じディレクトリになければ正しく動作しません。

アプリケーションを 100% スタンドアロンにしたいので、sqlite3.dll を RC_DATA としてプロジェクトに追加し、それを使用する必要があるときはいつでも (つまり、データベースを開くか保存するか)、アプリケーションと同じフォルダーに展開します。 . 開く操作または保存操作が完了したら、sqlite3.dll ファイルを削除したいと思います。そのファイルが存在することを誰も知らず、ライブラリの欠落などを心配する必要もありません。ライブラリをアプリケーション内に格納するというアイデアには、これを行う理由があります。アプリケーション (SQL) の機能の背後にあるものをエンドユーザーに知られたくないので、心配する必要もありません。ダイナミック リンク ライブラリがありません。)

問題は、sqlite3.dll を正常に抽出して操作に使用できることですが、(アプリケーションを閉じるまで) ファイルがアプリケーションによってロックされ、次のいずれかになります。

  1. アプリケーションを閉じずに、sqlite3.dll ファイルを強制的にロック解除する

  2. sqlite3.dll ファイルを強制的に削除します

もちろん、別の提案がない限り?

これを抽出して使用するサンプルを次に示します。私の部分から LoadLibrary などの直接呼び出しを行う必要はありません。sqlite3.dll がアプリケーションと同じディレクトリにある限り、Zeos Lib ユニットがこれを処理する必要があります。

procedure ExtractResource(ResName: String; Filename: String);
var
  ResStream: TResourceStream;
begin
  ResStream:= TResourceStream.Create(HInstance, ResName, RT_RCDATA);
  try
    ResStream.Position:= 0;
    ResStream.SaveToFile(Filename);
  finally
    ResStream.Free;
  end;
end;

//Open procedure
var
  sFileName: String = ExtractFilePath(ParamStr(0)) + 'Sqlite3.dll';    

if OpenDialog1.Execute then
begin
  ExtractResource('RES_SQLITE3', sFileName);
  ... //process my database
  ...
  ... // finished opening database
  if FileExists(sFileName) then
        DeleteFile(sFileName);
end;

編集

私がやろうとしていることはあまり実用的ではないと思います.STATUS_ACCESS_DENIEDが以前にコメントしたように、これは良い考えではありません. 私は、自分がやろうとしていることを進めないことが最善であると判断しました。

4

6 に答える 6

2

外部 dll に依存する代わりに、SQLite3 エンジンの静的リンクを使用することをお勧めします。.obj を .dcu SQLite3 ユニットに含める。

また、FastMM4 を SQlite3 エンジンのメモリ マネージャーとして使用する機能 (高速化) などのいくつかの優れた機能と、いくつかの優れた低レベル機能 (暗号化など) も追加される可能性があります。

たとえば、次を参照してください。

于 2011-05-17T07:54:00.727 に答える
1

簡単です、やらないでください。ファイルがロックされているのには理由があります。通常、他のプロセス (または自分自身のプロセス) がまだ使用しているなど、非常に正当な理由があります。ファイルがロックされている原因を特定し (例: Process Explorer を使用)、それが自分のプロセスである限り、すべてを解放したことを確認します。例えばFreeLibraryLoadLibraryなど...

絶対にファイルを削除する必要がある場合は、再起動時にファイルを削除するようにDeleteFile呼び出して失敗した場合に試してMoveFileExください。MOVEFILE_DELAY_UNTIL_REBOOT

使用中にファイルの「名前を変更」するために、別のファイルMoveFileまたはMoveFileExその間のファイルを使用できます (これは通常、同じパーティションで機能します)。ただし、これはファイル名に依存する場合にのみ必要であり、古い (ロックされた) 古いファイルがまだ存在する場合、プログラムの別のインスタンスがブロックされる可能性があります。

必要なことを実行する方法はあります、エンド ユーザーにリリースされるコードになるべきではありません。基本的には、たとえば、注入されたスレッドを使用して、ファイルをロックしているエンティティ内のファイルを閉じたりロック解除したりするハッカーに要約されます。でも形が悪い。それを避けるようにしてください。

于 2011-05-16T17:30:07.547 に答える
0

DLLを使用するのではなく、SQLiteライブラリexeにコンパイルできるソリューションがいくつかあります。本当に単一のファイルを実行可能にする必要がある場合は、これがはるかに優れたアプローチになると思います。DLLを抽出/削除することによって基本的に複製しようとしているのは、インストーラーの機能であり、実際にはすべきではありません。そのアプローチは、サポートの問題を求めているだけです。

また、dllを抽出してプログラムファイルディレクトリに保存するには、アプリを管理者権限で実行する必要がある場合があることにも注意してください。

実行可能ファイルと一緒にインストールされているDLLを使用できる場合は、DLLファイルの名前を別の名前(Database.dllなど)に変更し、新しいDLL名を指すようにzeosコードを変更できます。そうすると、SQLiteの機能はすぐにはわかりません。

于 2011-05-17T05:36:45.677 に答える
0

最初に、ファイルがまだ使用されていないことを確認する必要があります。あなたの場合、データベース ライブラリが DLL をロードし、まだ解放してないため、まだ使用されています。すでにデータベースから切断されているため、まだアクティブに使用されていない可能性がありますが、OS はそれを認識していません。DLL がロードされている場合、OS はそれがまだ必要であると見なし、削除を許可しません。

データベースに接続すると、Zeos は対応するデータベース ドライバー (この場合はTZSQLiteDriverZDbcSqLite.pasから) を見つけ、その関数をロードするように要求します。ただし、データベースから切断すると、Zeos はデータベース ドライバに関数のアンロードを要求しません。プログラムの存続期間中に複数の接続が確立および破棄される可能性がある典型的なプログラムでは、これは無駄です。

データベースへの開いている接続がないことが確実な場合は、自分で関数をアンロードできます。SQLite のローダーはZPlainSqLite3.pasにあります。ローダー オブジェクトを完全に解放することもできますが、後で問題が発生する可能性があります。これは、Zeos の他の部分が、必要なときにローダー オブジェクトがまだ残っていることを期待しているためです。代わりに、アンロードするように指示してください:

ZPlainSqLite3.Loader.FreeNativeLibrary;

これにより、オブジェクトがアンロードされたことを示すフラグが設定されるため、再度使用する必要がある場合は、すべてが再ロードされます。


本当に凝りたい場合はTZNativeLibraryLoader、ロード時にリソースから DLL を自動的にフェッチし、アンロード時にファイルを削除する独自の子孫を作成してみてください。そうすれば、プログラムの残りの部分でデータベース接続の有効期間について心配する必要がなくなります。他の人と同じように接続したり切断したりできます。

于 2011-05-16T17:51:21.203 に答える
0

LibraryLoaderZPlainSqLite3.pas の が DLL をロードしているようです。DLL を削除する前に、ファイナライズ セクションからコードを実行してみてください。

  if Assigned(LibraryLoader) then
     LibraryLoader.Free;
于 2011-05-16T17:45:30.347 に答える
0

使用中のファイルを削除することはできませんが、名前を変更することはできます。dll の名前を SQLITE3.DELETE.guid などに変更するだけです。起動時にアプリに sqlite.delete.* ファイルの削除を試行させることができるため、ファイルが解放された後に削除されます。-ドン

于 2011-05-16T17:24:17.080 に答える