【问题标题】:Delphi XE7 BDE Alias - setting it at run time?Delphi XE7 BDE Alias - 在运行时设置它?
【发布时间】:2016-05-16 07:17:36
【问题描述】:

我使用 Delphi XE7,我们的一个大型遗留应用程序仍然广泛使用带有 Paradox 表的 BDE。我知道 BDE 已被弃用,但我们对这个应用别无选择。

此应用当前在运行时和启动时设置 BDE 别名。它使用BDE提供的标准默认Session,并使用“TSession.AddStandardAlias”添加别名,并引用数据模块中定义的许多表。

我现在需要能够在应用程序运行后更改别名引用的文件夹路径,但发现它存在问题。基本上,它似乎可以工作,但是在更改别名后它仍然以某种方式引用以前的路径。甚至“TSession.GetAliasParams”也报告了新路径,但随后在 Bde.DBTables 中出现错误,因为它正在尝试访问不再存在的先前路径。

鉴于应用程序很大,我在以下示例项目中重现了类似的问题。如果有人愿意尝试,这是一个非常简单的应用程序,只有主窗体。您需要设置两个文件夹,并将任何 Paradox 表放到一个文件夹中,然后在“编辑”框中指定该文件夹的路径,然后按“设置别名路径”按钮,这将设置别名,然后写入按钮下方的标签,告诉您别名所指的路径。然后“查找表”按钮和编辑框使用“TSession.GetTableNames”查找是否存在表。

最简单的方法是设置两个文件夹“C:\TEMP\testBDE\path1”和“C:\TEMP\testBDE\path2”,然后在运行应用程序时将任何 Paradox 表放入 path1 “设置别名路径”按钮,然后按“查找表”按钮,它会报告该表存在。

Main form of sample app

然后改别名引用path2,为空,报指向path2,同时报表存在。然后很容易将表从path1移动到path2,然后它会报告表不存在。

任何建议将不胜感激。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    Button2: TButton;
    Edit2: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  Bde.DBTables;

const
  myAlias = 'ALIAS1';

function getPathFromAlias(tempAlais : String ): String;
var
  MyStringList : TStringList;
  i, k: integer;
  tempStr, newDirectory: String;
begin
  newDirectory:='';
  MyStringList := TStringList.Create;
  try
    Session.GetAliasParams(tempAlais,MyStringList);
    { fill stringlist with driver names }
    for i := 0 to MyStringList.count-1 do
    begin
      tempStr:= uppercase(trim(MyStringList.Strings[i]));
      k := pos('PATH=', tempStr);
      if k > 0 then
      begin
        delete(tempStr,1, k+4);
        newDirectory:=tempStr;
      end;
    end;
  finally
    MyStringList.Free;
  end;
  result:=newDirectory;
end;

procedure setAliases( apath : String);
var
  MyStringList : TStringList;
begin
(*
  MyStringList := TStringList.Create;
  try
    MyStringList.Add( 'PATH='+apath);
    MyStringList.Add( 'ENABLE BCD=FALSE');
    MyStringList.Add( 'DEFAULT DRIVER=PARADOX');
    Session.ConfigMode := cmSession;
    if Session.IsAlias( myAlias) then
      Session.ModifyAlias( myAlias, MyStringList)
    else
      Session.AddStandardAlias( myAlias, apath, 'PARADOX');
    Session.ConfigMode := cmSession;
  finally
    MyStringList.Free;
  end;
*)
  Session.ConfigMode := cmSession;
  if Session.IsAlias( myAlias) then
    Session.DeleteAlias( myAlias);
  Session.AddStandardAlias( myAlias, apath, 'PARADOX');
  Session.ConfigMode := cmSession;

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  setAliases( Edit1.Text);
  Label1.Caption := getPathFromAlias( myAlias);
end;

function TableExists(const aDataBaseName, aTableName:string): Boolean;
var
  TableNames: TStringList;
begin

  TableNames:=TStringList.Create;
  try
    Session.GetTableNames(aDatabaseName,'',True,False,TableNames);
    Result:=(TableNames.IndexOf(aTableName)<>-1);
  finally
    TableNames.Free;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  temps : String;
  myTable : TTable;
begin

  if TableExists( myAlias, Edit2.Text) then
    Label2.Caption := 'Exists'
  else
    Label2.Caption := 'Not found'
end;

end.

【问题讨论】:

  • 什么是操作系统?包含 BDE 别名的文件的完整路径是什么?
  • 抱歉,这是 Windows 7。我没有使用 BDE 配置文件,实际遗留应用程序中的别名是在运行时创建的,它们引用的路径来自另一个启动的应用程序旧版应用程序。这些路径基于原始安装文件夹。
  • Vista+ 具有所谓的“虚拟存储”,因此部分文件并没有真正位于应用程序读取和写入它们的位置。当您的应用程序保存/读取别名时,使用 SysInternals Process Monitor 之类的工具并拦截文件 I/O 日志,检查它们匹配的文件名,然后尝试查看磁盘上是否存在两个别名文件(默认为“idapi32.cfg”),在默认位置和虚拟商店中 - 它们可能重叠。还尝试“以管理员身份”运行您的应用程序 - 即使用“UAC 提升” - 这会暂时停用进程 AFAIR 的虚拟商店

标签: delphi


【解决方案1】:

您需要在更改别名属性之前关闭会话,然后再次打开

procedure TForm1.Button1Click(Sender: TObject);
begin
  Session.Close;

  setAliases( Edit1.Text);
  Label1.Caption := getPathFromAlias( myAlias);

  Session.Open;
end;

问题不在于无法识别路径更改,而是如果对正在使用的别名进行此类更改,则无法识别此类更改,正如您的测试程序中的此场景所示:

  1. 单击按钮 1:路径已更改
  2. 点击了按钮 2:找到表格
  3. 在编辑 1 中更改路径以引用原始别名路径
  4. 使用按钮 1 重置路径
  5. 点击了按钮 2:仍未找到表格

即如果您要做的第一件事是更改路径,那么别名确实反映了更改后的路径。问题是,一旦您使用了别名,对路径的更改不会随后反映。

通过关闭会话并重新打开它,您可以确保别名已正确“重置”。

在您的实际应用程序中,这可能会导致连锁反应,即在关闭并重新打开会话后需要重新打开数据库连接,尽管这是我的猜测。

替代方法

作为关闭会话以在运行时修改别名的替代方法,另一种方法可能是添加具有所需属性的新别名并将数据库连接重定向到该备用别名。

这显然也需要断开并重新连接重定向到此备用别名的所有数据库和查询。

【讨论】:

  • 谢谢。我在帮助中读到不建议关闭默认的 BDE 会话,这就是我没有这样做的原因,但你说的很有道理。也许我最好创建自己的会话,而不是使用默认会话?
  • 但是,我希望避免创建自己的会话,只是因为我担心这可能会对大型遗留应用程序产生什么影响。也许我别无选择。
  • @DavidT 至少在BDE Administrator GUI 中有一个特定的“应用更改”按钮“提交”调整,将别名文件存储到磁盘上,没有它,其他应用程序看不到任何更改。因此,您的应用操作中必须有类似的概念。我不知道是关闭会话还是有其他“应用更改”的方法。
  • 我认为因为现有的应用程序在启动时只设置了一次别名,并且从未更改过,这从来不是问题,但是现在我们需要在运行时更改它,这是一个问题。我将遵循您的建议并研究如何应用更改。谢谢
  • 另一种方法可能是在会话中创建一个备用别名并将您的连接切换到该别名,而不是修改现有别名的属性,但这可能涉及更多工作(难以说明在您的特定应用程序中是否禁止额外工作)。
猜你喜欢
  • 2015-07-15
  • 1970-01-01
  • 2015-02-25
  • 1970-01-01
  • 1970-01-01
  • 2014-10-28
  • 1970-01-01
  • 1970-01-01
  • 2015-03-07
相关资源
最近更新 更多