如何以编程方式找出 BDE 的共享内存区的实际位置和大小?
How to find out the BDE's shared memory area's actual location and size programmatically?
Borland 数据库引擎使用一个共享内存区域,该区域必须映射到所有 BDE 应用程序进程中的同一地址并发 运行宁在同一个 Windows 工作站。该区域的位置和大小由两个名为 SHAREDMEMLOCATION 和 SHAREDMEMSIZE 的设置决定。特别是位置设置只是一个起点,实际位置可能会完全不同。我不确定尺寸。
设置的副本似乎存储在几个地方。它们中的每一个都可能包含不同的值,特别是到达该位置的内容,其中 none 可能是 运行ning BDE 应用程序使用的 实际 值.
- 一个工作站范围的 BDE 配置文件,例如
C:\Program Files\Common Files\Borland Shared\BDE\idapi32.cfg
(如果是 "Run as Administrator",BDE 管理员应用程序将使用它)
- 一个用户特定的文件,例如
C:\Users\user-name\AppData\Local\Temp\_ISTMP1.DIR\_ISTMP0.DIR\idapi32.cfg
(安装程序显然已将其放置在 InstallShield 临时文件夹中,但无论如何 BDE 管理员使用的是由普通用户启动)
- Windows注册表,
HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database Engine\Settings\SYSTEM\INIT
,
- ...或其虚拟化版本,VirtualStore(如果是 64 位则 "Wow6432Node"Windows)
似乎至少如果注册表值存在,实际上这是 BDE 将 实际 查找的唯一地方,但 BDE 管理员实用程序无法更新注册表,which seems to be a common pitfall for BDE users。
恰好有一堆遗留的 BDE 应用程序需要支持,而这些应用程序在 Windows 系统中的 运行 不在我的控制范围内。一个问题是 SHAREDMEMSIZE 太小,它会导致“$2501”BDE 错误,我想为 SHAREDMEMSIZE 和 SHAREDMEMLOCATION 的实际使用的有效值添加自动检查,以便应用程序可以自我诊断问题。
使 SHAREDMEMLOCATION "interesting" 的原因是 BDE 根本不必在该位置创建其共享内存区域。这个过程是这样的:
- 情况A)如果我是第一个BDE应用,共享内存区还没有分配:
- 尝试在 SHAREDMEMLOCATION 分配 SHAREDMEMSIZE 字节的内存。
- 如果space现在对我来说不是免费的,那么看看...任何其他地方,使用某种算法,把它放在任何有免费连续地址的地方space SHAREDMEMSIZE 字节范围!哇哦
- 情况B) 如果我不是第一个运行ning BDE应用程序,并且共享内存区域已经存在于这个工作站上
- 尝试绘制该区域的地图(无论它在哪里)
- 如果我不能将它映射到这个进程,因为已经有一些东西(代码或数据或任何东西),然后给出“$210D”错误,"Shared memory conflict"
只有在最后一个BDE应用程序进程关闭后,共享内存区域才会被重新放置。 (如果这看起来很有趣,您可以观察它是如何与 Sysinternals VMMap 工具一起工作的)
正如你所想象的,共享内存区域在情况A中是否适合,以及在情况B中是否恰好适合下一个应用程序进程,可以稍微随机一些。例如,如果更改大小参数,可能会导致 "fixing" $210D 错误,只是因为较小或较大的块碰巧适合其他地方,而恰好适合某些应用程序组合(以某种顺序启动) .人们尝试使用 BDE Administrator 程序修复它并没有真正帮助,这对于毫无戒心的用户或管理员来说看起来非常有说服力,但实际上并没有更改会对实际发生的事情产生影响的注册表设置。 (这可能是一个错误,但那又怎样)
所以我的问题是,如何以编程方式检查 BDE 实际 使用的大小和位置?我知道如何阅读配置文件,我可以查询 BDE 本身,它会根据文件中的内容报告其配置。不幸的是,它根本不需要对文件中的设置进行操作,因此无论报告什么值,都可能不是有效设置。我可以读取注册表值,但即便如此也可能无法判断共享内存区域的实际位置。
我查看了 idapi32.dll 导出的函数,但找不到任何可能报告共享内存区域的实际位置和大小的内容。我什至尝试 "de-compile" BDE.DCU,但它似乎只使用了 idapi DLL 函数,并且离肮脏的内部细节更远。
我在想,我可以尝试扫描 BDE 的内部内存区域并尝试定位地址的实例,但我认为肯定必须有一个函数或其他东西吗?
到目前为止,我在解决 BDE 错误方面遇到的最大问题是我的应用程序(实际上是每个应用程序)在单元初始化链的早期就更改了注册表设置。当然,更改只会在 VirtualStore 下发生,但至少 BDE 似乎从那里读取值。但是,如果出现 $2501(内存不足)或 $210D(位置冲突)错误,能够判断共享内存区域的实际位置和大小是否与我的程序尝试使用的设置不同会很好。
编辑:如果每个人都可以尽量避免解释诸如天空通常是什么颜色,或者 Delphi 应用程序有什么样的数据库选项之类的事情。谢谢。 :)
因为我似乎无法快速获得 Whosebug 的答案,所以我对它的工作原理进行了逆向工程。我查看了 idapi32.dll 中的函数名称并注意到了一些有趣的名称,尤其是 OsSetSharedPtr 和 OsGetSharedPtr。在 Delphi 的模块列表和 CPU window 的帮助下,我在函数入口点设置了断点,并在 BDE 初始化和 de 时查看了参数和 return 值- 初始化自己。这是一些示例代码,如何调用函数 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可以知道大小。函数 return 值似乎是相同的地址,我的示例只是没有使用 return 值。
我不对此信息的正确性承担任何责任。如果你使用这个逆向工程kludge/hack,而发生了不好的事情,那就怪你自己吧。
Borland 数据库引擎使用一个共享内存区域,该区域必须映射到所有 BDE 应用程序进程中的同一地址并发 运行宁在同一个 Windows 工作站。该区域的位置和大小由两个名为 SHAREDMEMLOCATION 和 SHAREDMEMSIZE 的设置决定。特别是位置设置只是一个起点,实际位置可能会完全不同。我不确定尺寸。
设置的副本似乎存储在几个地方。它们中的每一个都可能包含不同的值,特别是到达该位置的内容,其中 none 可能是 运行ning BDE 应用程序使用的 实际 值.
- 一个工作站范围的 BDE 配置文件,例如
C:\Program Files\Common Files\Borland Shared\BDE\idapi32.cfg
(如果是 "Run as Administrator",BDE 管理员应用程序将使用它) - 一个用户特定的文件,例如
C:\Users\user-name\AppData\Local\Temp\_ISTMP1.DIR\_ISTMP0.DIR\idapi32.cfg
(安装程序显然已将其放置在 InstallShield 临时文件夹中,但无论如何 BDE 管理员使用的是由普通用户启动) - Windows注册表,
HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database Engine\Settings\SYSTEM\INIT
, - ...或其虚拟化版本,VirtualStore(如果是 64 位则 "Wow6432Node"Windows)
似乎至少如果注册表值存在,实际上这是 BDE 将 实际 查找的唯一地方,但 BDE 管理员实用程序无法更新注册表,which seems to be a common pitfall for BDE users。
恰好有一堆遗留的 BDE 应用程序需要支持,而这些应用程序在 Windows 系统中的 运行 不在我的控制范围内。一个问题是 SHAREDMEMSIZE 太小,它会导致“$2501”BDE 错误,我想为 SHAREDMEMSIZE 和 SHAREDMEMLOCATION 的实际使用的有效值添加自动检查,以便应用程序可以自我诊断问题。
使 SHAREDMEMLOCATION "interesting" 的原因是 BDE 根本不必在该位置创建其共享内存区域。这个过程是这样的:
- 情况A)如果我是第一个BDE应用,共享内存区还没有分配:
- 尝试在 SHAREDMEMLOCATION 分配 SHAREDMEMSIZE 字节的内存。
- 如果space现在对我来说不是免费的,那么看看...任何其他地方,使用某种算法,把它放在任何有免费连续地址的地方space SHAREDMEMSIZE 字节范围!哇哦
- 情况B) 如果我不是第一个运行ning BDE应用程序,并且共享内存区域已经存在于这个工作站上
- 尝试绘制该区域的地图(无论它在哪里)
- 如果我不能将它映射到这个进程,因为已经有一些东西(代码或数据或任何东西),然后给出“$210D”错误,"Shared memory conflict"
只有在最后一个BDE应用程序进程关闭后,共享内存区域才会被重新放置。 (如果这看起来很有趣,您可以观察它是如何与 Sysinternals VMMap 工具一起工作的)
正如你所想象的,共享内存区域在情况A中是否适合,以及在情况B中是否恰好适合下一个应用程序进程,可以稍微随机一些。例如,如果更改大小参数,可能会导致 "fixing" $210D 错误,只是因为较小或较大的块碰巧适合其他地方,而恰好适合某些应用程序组合(以某种顺序启动) .人们尝试使用 BDE Administrator 程序修复它并没有真正帮助,这对于毫无戒心的用户或管理员来说看起来非常有说服力,但实际上并没有更改会对实际发生的事情产生影响的注册表设置。 (这可能是一个错误,但那又怎样)
所以我的问题是,如何以编程方式检查 BDE 实际 使用的大小和位置?我知道如何阅读配置文件,我可以查询 BDE 本身,它会根据文件中的内容报告其配置。不幸的是,它根本不需要对文件中的设置进行操作,因此无论报告什么值,都可能不是有效设置。我可以读取注册表值,但即便如此也可能无法判断共享内存区域的实际位置。
我查看了 idapi32.dll 导出的函数,但找不到任何可能报告共享内存区域的实际位置和大小的内容。我什至尝试 "de-compile" BDE.DCU,但它似乎只使用了 idapi DLL 函数,并且离肮脏的内部细节更远。
我在想,我可以尝试扫描 BDE 的内部内存区域并尝试定位地址的实例,但我认为肯定必须有一个函数或其他东西吗?
到目前为止,我在解决 BDE 错误方面遇到的最大问题是我的应用程序(实际上是每个应用程序)在单元初始化链的早期就更改了注册表设置。当然,更改只会在 VirtualStore 下发生,但至少 BDE 似乎从那里读取值。但是,如果出现 $2501(内存不足)或 $210D(位置冲突)错误,能够判断共享内存区域的实际位置和大小是否与我的程序尝试使用的设置不同会很好。
编辑:如果每个人都可以尽量避免解释诸如天空通常是什么颜色,或者 Delphi 应用程序有什么样的数据库选项之类的事情。谢谢。 :)
因为我似乎无法快速获得 Whosebug 的答案,所以我对它的工作原理进行了逆向工程。我查看了 idapi32.dll 中的函数名称并注意到了一些有趣的名称,尤其是 OsSetSharedPtr 和 OsGetSharedPtr。在 Delphi 的模块列表和 CPU window 的帮助下,我在函数入口点设置了断点,并在 BDE 初始化和 de 时查看了参数和 return 值- 初始化自己。这是一些示例代码,如何调用函数 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可以知道大小。函数 return 值似乎是相同的地址,我的示例只是没有使用 return 值。
我不对此信息的正确性承担任何责任。如果你使用这个逆向工程kludge/hack,而发生了不好的事情,那就怪你自己吧。