delphi - 如何以编程方式找出BDE共享存储区的实际位置和大小?

标签 delphi bde

Borland数据库引擎使用共享内存区域,该内存区域必须映射到在同一Windows工作站中同时运行的所有BDE应用程序进程中的相同地址中。该区域的位置和大小受称为SHAREDMEMLOCATION和SHAREDMEMSIZE的两个设置的指导。特别是位置设置仅作为起点,实际位置可能最终会完全不同。我不确定尺寸。

设置的副本似乎存储在多个位置。它们每个可能包含不同的值,尤其是位置值,而这些值都不是正在运行的BDE应用程序使用的实际值。


工作站范围的BDE配置文件,例如C:\Program Files\Common Files\Borland Shared\BDE\idapi32.cfg(如果BDE Administrator应用程序是“以管理员身份运行”,则BDE Administrator应用程序将使用该文件)
特定于用户的文件,例如C:\Users\user-name\AppData\Local\Temp\_ISTMP1.DIR\_ISTMP0.DIR\idapi32.cfg(安装程序显然已将其放置在InstallShield临时文件夹中,但无论如何,如果普通用户启动它,BDE Administrator都会使用该文件)
Windows注册表HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database Engine\Settings\SYSTEM\INIT
...或其虚拟化版本VirtualStore(如果是64位Windows,则为“ Wow6432Node”)


看来,至少如果注册表值存在,实际上这是BDE实际看起来的唯一位置,但是BDE Administrator实用程序无法更新注册表which seems to be a common pitfall for BDE users

我需要支持一堆旧的BDE应用程序,这些应用程序在不受我控制的Windows系统中运行。一个问题是SHAREDMEMSIZE太小,并且会导致“ $ 2501” BDE错误,我想为SHAREDMEMSIZE和SHAREDMEMLOCATION添加一个用于实际使用的有效值的自动检查,以便应用程序可以自我诊断问题。

使SHAREDMEMLOCATION变得“有趣”的原因是BDE不必在该位置完全创建其共享内存区域。该过程如下所示:


情况A)如果我是第一个BDE应用程序,并且尚未分配共享内存区域:


尝试在SHAREDMEMLOCATION分配SHAREDMEMIZE内存字节。
如果这个空间现在对我来说不是空闲的,那么请使用某种算法在其他任何地方查看,并将其放置在SHAREDMEMSIZE字节的自由连续地址空间范围内的任何地方!哇。

情况B)如果我不是第一个运行的BDE应用程序进程,并且此工作站上已经存在共享内存区域


尝试映射该区域(无论它在哪里)
如果我无法将其映射到此进程,因为已经有东西(代码,数据或任何东西),请给出“ $ 210D”错误,“共享内存冲突”



仅在最后一个BDE应用程序进程关闭后,才可以再次放置共享内存区域。 (如果这看起来很有趣,您可以观察它如何与Sysinternals VMMap工具一起使用)

可以想象,共享存储区在哪里以及是否适合情况A,如果碰巧适合情况B的下一个应用程序,则可以是稍微随机的。例如,如果您更改大小参数,可能会导致“修复” $ 210D错误,只是因为一个较小的块或较大的块恰好适合某个适合某些应用程序组合的其他地方(以某种顺序启动)。人们尝试使用BDE Administrator程序对其进行修复实际上并没有帮助,该程序对于毫无戒心的用户或管理员来说非常有说服力,但是实际上并没有更改将对实际情况产生影响的注册表设置。 (这可能是一个错误,但是怎么回事)

所以我的问题是,如何以编程方式检查BDE实际使用的大小和位置?我知道如何读取配置文件,并且可以查询BDE本身,并且BDE根据文件中的内容报告其配置。不幸的是,它不一定完全作用于文件中的设置,因此,无论报告什么值,都可能不是有效的设置。我可以读取注册表值,但是即使这样也可能无法告诉您共享内存区域实际上在哪里。

我看过idapi32.dll导出的函数,但是找不到任何可能报告共享内存区域的实际位置和大小的东西。我什至尝试“反编译” BDE.DCU,但它似乎只是使用idapi DLL函数,而且离脏的内部细节还很远。

我在想,我可以尝试扫描BDE的内部存储区,并尝试找到该地址的实例,但是我认为肯定要有一个功能或某些功能吗?

到目前为止,解决BDE错误的最佳方法是,我的应用程序(实际上每个错误)都在单元初始化链中很早就更改了注册表设置。当然,所做的更改只会在VirtualStore之下进行,但是至少BDE似乎从那里读取值。但是,如果出现$ 2501(内存不足)或$ 210D(位置冲突)错误,最好能够告诉您共享内存区域的实际位置和大小是否与我的程序尝试使用的设置不同。

编辑:如果每个人都可以尝试避免解释诸如天空通常是什么颜色,或者Delphi应用程序具有哪种数据库选项之类的信息。谢谢。 :)

最佳答案

看来我不会很快得到StackOverflow的答案,所以我对它的工作方式进行了反向工程。我查看了idapi32.dll中的函数名称,并注意到了一些有趣的名称,尤其是OsSetSharedPtr和OsGetSharedPtr。在Delphi的“模块”列表和CPU窗口的帮助下,我在函数入口点上设置了断点,并在BDE自身初始化和取消初始化时查看了参数和返回值。这是一些示例代码,如何调用函数idapi32.OsGetSharedPtr()

type PCardinal = ^Cardinal;

type
  TOsGetSharedPtrFunc = function (Par1 : Cardinal; Par2 : PCardinal) : Cardinal; stdcall;

procedure TForm1.Button1Click(Sender: TObject);
var
  OsGetSharedPtrFunc : TOsGetSharedPtrFunc;
  base, size : Cardinal;
  lib : HMODULE;
begin
  lib := LoadLibrary('idapi32.dll');
  if lib = 0 then
    ShowMessage('Could not LoadLibrary().')
  else
    try
      OsGetSharedPtrFunc := GetProcAddress(lib, 'OsGetSharedPtr');
      if @OsGetSharedPtrFunc <> nil then
      begin
        OsGetSharedPtrFunc(9, @base);
        OsGetSharedPtrFunc($A, @size);
        ShowMessageFmt('%x %x', [base, size]);
      end
      else
        ShowMessage('Could not GetProcAddress().');
    finally
      FreeLibrary(lib);
    end;
end;


以数字9作为第一个参数,您可以询问共享存储区的基本位置是什么,而以数字10,则可以得到其大小。函数的返回值似乎是相同的地址,我的示例只是不使用返回值。

我对这些信息的正确性不承担任何责任。如果您使用此反向工程的kludge / hack,但发生了不好的事情,请怪自己。

关于delphi - 如何以编程方式找出BDE共享存储区的实际位置和大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43142444/

相关文章:

delphi - 组件的默认属性值

delphi - 如何使用 Delphi 7 ADOQuery.ExecSQL 更新 SQL Server 上的 DateTime 并保留毫秒?

delphi - BDE和斯洛伐克语。有驱动程序吗?

c++ - C++ Builder 6 和 Windows 7 64 位上的 ADOQuery

delphi - Delphi XE4 64位中的SendMessageTimeout产生访问冲突

Delphi正确使用TMultiView

delphi - 将具有通用参数的类传递给Delphi中的另一个类

delphi - 如何忽略TQuery中的一些参数

delphi - TQuery 上的 AfterScroll 和 AfterOpen

delphi - BDE、Delphi、ODBC、SQL Native Client 和死锁