OS 的位数是否重要,或者它只是我需要担心的应用程序?
Does the bitness of the OS ever matter, or is it just the application I need to worry about?
一些假设:(如有错误请指正)
忽略 16 位的东西,VBA 在 32 位或 64 位 Office 主机上可以是 运行。 64 位 Office 只能 运行 在 64 位 OS 上,而您可以 运行 32 位 office 在 32 或 64 上Windows/macOS/other 操作系统的位版本。
从 VBA7 开始,我们有 LongPtr
类型,在 32 位 Office (#Win64 = False
) 上变成 Long
,LongLong
在 64 位 Office (#Win64 = True
) 上,不考虑 OS 位数
我的问题: 在处理指针(内存中的地址)的 API 中,OS 位数是否重要,或者只是应用程序 运行 宁我们关心的代码(32/64 位办公室 host/VBA)?
目前的理解:
一方面我明白为什么这可能无关紧要:
- VBA 运行ning in 32-bit Excel 将有一个32位地址space(不管OS)
- 因此,任何指向它自己内存的指针都应该是 32 位的(即
Long
s - LongPtr
给了我们这个)
- 类似 64 位 VBA(必须是 64 位 OS,但实际上可以是任何地方)有一个 64 位地址 space(每个指针本身就是 64 位long 并且指的是 64 位宽的内存块)
- 因此,任何指向它自己内存的指针都应该是 64 位的(即
LongLong
s - LongPtr
给了我们这个)
- 因此
LongPtr
准确地表示了一个指向我的代码自身内存的指针,而不管 OS 位数
但是我可以想象OS位数可能很重要
的时代
- 运行 32 位 VBA 在 64 位 OS 上,但想要引用不同 64 位应用程序的内存区域,
LongPtr
type 将评估为 Long
并且太短而无法表示 OS. 中可用的最大指针大小
- 类似地,64 位 VBA 访问 32 位应用程序的内存会发现其指针类型太大而无法容纳地址
- 现在备受信任的
LongPtr
类型实际上是 错误的长度 来表示指向 VBA 自身地址之外的内存地址的指针 space!
现在可能会出现问题,具体取决于 OS 位数,而不是 Office/VBA 位数。如果我们在 32 位 OS 上 运行ning VBA7,那么 LongPtr
将是您可能想要扔给它的任何内存块的正确长度;它在 99.9% 的情况下都是合适的指针数据类型,因为 OS 所做的一切都是 32 位的(忽略 16 位)。
然而,相同的 32 位 VBA7 代码而不是 运行ning 在 64 位 OS 上 运行 在尝试使用 [=11] 时会遇到困难=] 来保存 32 位地址。我觉得在 64 位上混合使用 32 位和 64 位应用程序是很常见的 OS,所以这可能是一个真正的问题。
32 位 VBA6 和更早的应用程序 运行ning 在 32 位和 64 位操作系统上可能会面临类似的问题,只是没有 LongPtr
的帮助
现在我明白这是一个非常人为的情况,谁会想要访问另一个应用程序的内存,对吧?事实上,它是如此做作,以至于我不确定我是否能想出一个重要且值得担心的情况。一个应用程序能否获得另一个具有不同位数的应用程序的内存地址?也许有一些读写保护可以防止这种情况。
也许访问另一个应用程序的 window 句柄就是这样一种情况;那是 public 内存,也许 window 句柄的位数反映了应用程序或操作系统的位数,在这种情况下,我的 32 位 VBA 想要保留对 64 位 Hwnd
的引用,我不确定...
PS 我知道除了指针长度之外,在某些情况下 OS 位数可能很重要。我知道一个; SetWindowLong
函数需要在 64 位和 32 位 Windows 上进行不同的声明——尽管 IIUC 现在已经用 SetWindowLongPtr
函数解决了,两者是相同的。但是了解任何其他类似的怪癖都会很有用,我在这里只关注指针长度,因为我有一个需要特定信息的问题。
PPS 想一想,你甚至可以在编译时获得 OS 位;我想你可以从 MAC_OFFICE_VERSION
推断出来,而 ofc Win64 = True
意味着 64 位 Office 和事实上的 64 位 OS。但我不确定是否有办法判断 32 位 VBA 是否在 64 位 Windows...
上 运行ning
当然,OS 的位数很重要。
您可以看到 我们需要 64 位 32 位办公室的特定代码 Windows(正确注册 COM DLL 以便在 32 位应用程序中使用)。
我在那里使用的测试是:
#If Win64 Then
Const Win64 = True
#Else
Const Win64 = False
#End If
If Not Win64 And Environ$("ProgramW6432") <> vbNullString Then
'32 bits Office on Win 64
Else
'Either 32-bits Windows, or 64-bits Office on 64-bits windows
End If
Afaik,你无法在编译时确定这一点,只能在运行时确定。
使用外部 APIs/applications 时,它通常很重要。我不打算列出可能的情况,因为它永远不会完整,但有很多可能的情况。
对于内存访问,这应该无关紧要,因为访问另一个进程 non-global 内存应该会引发段错误并且 hard-crash 您的应用程序。如果您使用的是全局变量,那真的不是问题。
A LongPtr
对于您的过程总是正确的。您无需担心它的大小。您不需要 WIN64
常量即可使用它。事实上,您 通常 唯一需要的常量是 VBA7
,它告诉您 LongPtr
是否可用。如果是,使用它,如果不是,你肯定是 x86 所以使用 Long
.
此外,Windows x64 有一个名为 WoW64 的完整兼容层。作为一个在 64 位 Windows 上运行的 32 位应用程序 运行,你不会注意到任何东西,你 运行 就好像 OS 是 32 位的。您的指针大小是四个字节,您的 pointer-sized 数据类型(例如 HWND
s 是四个字节,所以再次强调,如果您只参考 VBA7
和在必须出现 pointer-sized 参数的所有地方正确放置 LongPtr
。
因此,对于流程中的日常事务,以及与 OS 及其对象的交互,您无需担心 您自己或OS 的位数,您也不需要 WIN64
常量。
现在,您特别提到获取和使用对位数与您自己不同的进程有效的指针。是的,这可能是个问题,但这个问题并不特定于 VBA。
如果作为 VBA 应用程序,您发现自己需要读取任意位数的任意进程的内存,您确实需要将自己的位数与其位数进行比较。此时你 可以 使用 WIN64
常量,但在这种情况下在 运行 时检查 Len(long_ptr_variable)
比检查 Len(long_ptr_variable)
更方便有单独的代码分支。
已完成测试,
- 如果你的位数更高,你可以无限制地读取其他进程的内存。
- 如果您的位数较小,您可以在 4 字节指针允许的范围内达到大家伙的虚拟内存。
- 如果你需要超越那个,你将不得不失败 (or not)。
但请注意,即使在这种情况下,您也不关心 OS 位数或 WIN64
常量!您只关心您的进程位数与其他进程位数。
一些假设:(如有错误请指正)
忽略 16 位的东西,VBA 在 32 位或 64 位 Office 主机上可以是 运行。 64 位 Office 只能 运行 在 64 位 OS 上,而您可以 运行 32 位 office 在 32 或 64 上Windows/macOS/other 操作系统的位版本。
从 VBA7 开始,我们有 LongPtr
类型,在 32 位 Office (#Win64 = False
) 上变成 Long
,LongLong
在 64 位 Office (#Win64 = True
) 上,不考虑 OS 位数
我的问题: 在处理指针(内存中的地址)的 API 中,OS 位数是否重要,或者只是应用程序 运行 宁我们关心的代码(32/64 位办公室 host/VBA)?
目前的理解:
一方面我明白为什么这可能无关紧要:
- VBA 运行ning in 32-bit Excel 将有一个32位地址space(不管OS)
- 因此,任何指向它自己内存的指针都应该是 32 位的(即
Long
s -LongPtr
给了我们这个) - 类似 64 位 VBA(必须是 64 位 OS,但实际上可以是任何地方)有一个 64 位地址 space(每个指针本身就是 64 位long 并且指的是 64 位宽的内存块)
- 因此,任何指向它自己内存的指针都应该是 64 位的(即
LongLong
s -LongPtr
给了我们这个) - 因此
LongPtr
准确地表示了一个指向我的代码自身内存的指针,而不管 OS 位数
但是我可以想象OS位数可能很重要
的时代- 运行 32 位 VBA 在 64 位 OS 上,但想要引用不同 64 位应用程序的内存区域,
LongPtr
type 将评估为Long
并且太短而无法表示 OS. 中可用的最大指针大小
- 类似地,64 位 VBA 访问 32 位应用程序的内存会发现其指针类型太大而无法容纳地址
- 现在备受信任的
LongPtr
类型实际上是 错误的长度 来表示指向 VBA 自身地址之外的内存地址的指针 space!
现在可能会出现问题,具体取决于 OS 位数,而不是 Office/VBA 位数。如果我们在 32 位 OS 上 运行ning VBA7,那么 LongPtr
将是您可能想要扔给它的任何内存块的正确长度;它在 99.9% 的情况下都是合适的指针数据类型,因为 OS 所做的一切都是 32 位的(忽略 16 位)。
然而,相同的 32 位 VBA7 代码而不是 运行ning 在 64 位 OS 上 运行 在尝试使用 [=11] 时会遇到困难=] 来保存 32 位地址。我觉得在 64 位上混合使用 32 位和 64 位应用程序是很常见的 OS,所以这可能是一个真正的问题。
32 位 VBA6 和更早的应用程序 运行ning 在 32 位和 64 位操作系统上可能会面临类似的问题,只是没有 LongPtr
现在我明白这是一个非常人为的情况,谁会想要访问另一个应用程序的内存,对吧?事实上,它是如此做作,以至于我不确定我是否能想出一个重要且值得担心的情况。一个应用程序能否获得另一个具有不同位数的应用程序的内存地址?也许有一些读写保护可以防止这种情况。
也许访问另一个应用程序的 window 句柄就是这样一种情况;那是 public 内存,也许 window 句柄的位数反映了应用程序或操作系统的位数,在这种情况下,我的 32 位 VBA 想要保留对 64 位 Hwnd
的引用,我不确定...
PS 我知道除了指针长度之外,在某些情况下 OS 位数可能很重要。我知道一个; SetWindowLong
函数需要在 64 位和 32 位 Windows 上进行不同的声明——尽管 IIUC 现在已经用 SetWindowLongPtr
函数解决了,两者是相同的。但是了解任何其他类似的怪癖都会很有用,我在这里只关注指针长度,因为我有一个需要特定信息的问题。
PPS 想一想,你甚至可以在编译时获得 OS 位;我想你可以从 MAC_OFFICE_VERSION
推断出来,而 ofc Win64 = True
意味着 64 位 Office 和事实上的 64 位 OS。但我不确定是否有办法判断 32 位 VBA 是否在 64 位 Windows...
当然,OS 的位数很重要。
您可以看到
我在那里使用的测试是:
#If Win64 Then
Const Win64 = True
#Else
Const Win64 = False
#End If
If Not Win64 And Environ$("ProgramW6432") <> vbNullString Then
'32 bits Office on Win 64
Else
'Either 32-bits Windows, or 64-bits Office on 64-bits windows
End If
Afaik,你无法在编译时确定这一点,只能在运行时确定。
使用外部 APIs/applications 时,它通常很重要。我不打算列出可能的情况,因为它永远不会完整,但有很多可能的情况。
对于内存访问,这应该无关紧要,因为访问另一个进程 non-global 内存应该会引发段错误并且 hard-crash 您的应用程序。如果您使用的是全局变量,那真的不是问题。
A LongPtr
对于您的过程总是正确的。您无需担心它的大小。您不需要 WIN64
常量即可使用它。事实上,您 通常 唯一需要的常量是 VBA7
,它告诉您 LongPtr
是否可用。如果是,使用它,如果不是,你肯定是 x86 所以使用 Long
.
此外,Windows x64 有一个名为 WoW64 的完整兼容层。作为一个在 64 位 Windows 上运行的 32 位应用程序 运行,你不会注意到任何东西,你 运行 就好像 OS 是 32 位的。您的指针大小是四个字节,您的 pointer-sized 数据类型(例如 HWND
s 是四个字节,所以再次强调,如果您只参考 VBA7
和在必须出现 pointer-sized 参数的所有地方正确放置 LongPtr
。
因此,对于流程中的日常事务,以及与 OS 及其对象的交互,您无需担心 您自己或OS 的位数,您也不需要 WIN64
常量。
现在,您特别提到获取和使用对位数与您自己不同的进程有效的指针。是的,这可能是个问题,但这个问题并不特定于 VBA。
如果作为 VBA 应用程序,您发现自己需要读取任意位数的任意进程的内存,您确实需要将自己的位数与其位数进行比较。此时你 可以 使用 WIN64
常量,但在这种情况下在 运行 时检查 Len(long_ptr_variable)
比检查 Len(long_ptr_variable)
更方便有单独的代码分支。
已完成测试,
- 如果你的位数更高,你可以无限制地读取其他进程的内存。
- 如果您的位数较小,您可以在 4 字节指针允许的范围内达到大家伙的虚拟内存。
- 如果你需要超越那个,你将不得不失败 (or not)。
但请注意,即使在这种情况下,您也不关心 OS 位数或 WIN64
常量!您只关心您的进程位数与其他进程位数。