如果操作系统认为它仍在使用中,如何在完成后删除SQLite DLL?

时间:2011-05-16 16:32:48

标签: delphi sqlite unlock zeos

如何解锁或删除正在使用的文件,以便我可以将其删除?有问题的文件由我自己的应用程序使用。

更具体地说,我的应用程序正在使用免费软件Zeos Lib。打开并保存数据库时,sqlite3.dll文件必须与我的应用程序位于同一目录中才能正常工作。

我希望我的应用程序是100%独立的,所以我将sqlite3.dll作为RC_DATA添加到我的项目中,每当我需要使用它(即打开或保存数据库)时,我将它提取到同一个文件夹作为我的申请。一旦打开或保存操作完成,我想删除sqlite3.dll文件,没有人会知道它在那里或者不得不担心丢失库等。(虽然我可以理解你们中的一些人可能不喜欢将库存储在应用程序中的想法,我有理由这样做:我不希望我的最终用户知道我的应用程序(SQL)的功能背后的原因,他们也不需要担心缺少动态链接库。)

问题是,我可以成功提取sqlite3.dll并将其用于我的操作,但该文件被我的应用程序锁定(直到我关闭我的应用程序),这将我带到:

  1. 强制解锁sqlite3.dll文件,而不关闭我的应用程序

  2. 强制删除sqlite3.dll文件

  3. 除非有其他建议吗?

    以下是提取和使用它的示例。我不需要直接调用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进行了评论,这不是一个好主意。我已经决定最好不要继续我的目标。

6 个答案:

答案 0 :(得分:2)

您最好使用SQLite3引擎的静态链接,而不是依赖外部dll。将.obj包含在.dcu SQLite3单元中。

它还将添加一些不错的功能,例如使用FastMM4作为SQlite3引擎的内存管理器(加速),以及潜在的一些不错的低级功能(如加密)。

参见例如:

答案 1 :(得分:1)

简单,不要这样做。文件被锁定的原因是有原因的。通常它是一个非常好的理由,比如一些其他进程(甚至是你自己的)仍在使用它。找出阻止文件锁定的内容(例如使用Process Explorer),只要这是您的过程,请确保您释放所有内容。例如。 FreeLibrary等之后的LoadLibrary ...

如果您绝对必须删除该文件,请尝试DeleteFile,如果失败,请使用MoveFileExMOVEFILE_DELAY_UNTIL_REBOOT联系,以便在重新启动时删除该文件。

您可以在其间使用另一个MoveFileMoveFileEx来重命名文件(这通常适用于同一分区)。但是,只有在依赖文件名时才需要这样做,因此如果旧的(已锁定的)陈旧文件仍然存在,则程序的另一个实例可能会被阻止。

方法可以执行您想要的操作,但它们不应该以发布给最终用户的代码结束。它基本上可以归结为hackery,例如 - 使用注入的线程来关闭/解锁保持锁定的实体中的文件。但这是糟糕的形式。尽量避免它。

答案 2 :(得分:0)

虽然您无法删除正在使用的文件,但您可以重命名该文件。只需将dll重命名为SQLITE3.DELETE.guid。在启动时,您可以让您的应用程序尝试删除任何sqlite.delete。*文件,以便在文件释放后它将消失。 -don

答案 3 :(得分:0)

看起来ZPlainSqLite3.pas中的LibraryLoader正在加载DLL。在尝试删除DLL之前,您可以尝试运行完成部分中的代码:

  if Assigned(LibraryLoader) then
     LibraryLoader.Free;

答案 4 :(得分:0)

您应首先确保该文件仍未使用。在您的情况下, 仍在使用中,因为数据库库已加载DLL但尚未释放它。由于您已经与数据库断开连接,它可能还没有在活动中使用,但操作系统不知道 - 如果加载了DLL,操作系统会认为它仍然需要并且不允许删除。

当您连接到数据库时,Zeos会从 ZDbcSqLite.pas 中找到相应的数据库驱动程序(在本例中为TZSQLiteDriver),并要求它加载其功能。但是当您从数据库断开连接时,Zeos不会要求数据库驱动程序卸载其功能。这在典型的程序中是浪费的,在程序的整个生命周期中可能会建立和销毁多个连接。

如果您确定没有与数据库的开放连接,则可以自行卸载这些功能。 SQLite的加载器位于 ZPlainSqLite3.pas 中。虽然你可以完全释放加载器对象,但这可能会导致以后出现问题,因为Zeos的其他部分期望它在需要时仍然存在。相反,只需告诉它卸载:

ZPlainSqLite3.Loader.FreeNativeLibrary;

这会导致对象设置指示它被卸载的标志,因此如果您需要再次使用它,它将重新加载所有内容。


如果你真的想要开心,你可以尝试编写自己的TZNativeLibraryLoader后代,在加载时自动从资源中获取DLL,并在卸载时删除文件。然后,您不必担心程序其余部分的数据库连接生命周期。你可以像其他人一样连接和断开连接。

答案 5 :(得分:0)

有一些解决方案可用于将SQLite库编译到您的exe中,而不是使用DLL。如果你真的必须有一个文件可执行文件,我认为这是一个好得多的方法。你基本上试图通过提取/删除DLL来复制的是安装程序的功能,你真的不应该。这种方法只是要求支持问题。

另请注意,您的应用可能需要以管理员权限运行才能解压缩并将其保存到程序文件目录中。

如果你可以使用与可执行文件一起安装的DLL,你可以将DLL文件重命名为其他东西(即Database.dll),并在zeos代码中进行更改,使其指向新的DLL名称。然后,SQLite功能不会立即明显。