黑客» 10.06.2019 (一) 14:01在我认真沉浸于对内部世界和 VB6 设备的研究之前,我和许多其他人一样,脑海中有这样的想法:VB 是主要产品,而 VBA 是副产品,是在功能方面削减主要产品并将其附加到 Office 应用程序(如 Excel、Word)的结果。但经常发生的情况是,外行人对事物结构的想法,建立在试图预测这种结构的基础上,可能与真正的结构截然不同。在这种情况下,这正是我们的情况:事实上,一切都恰恰相反,VBA不是VB创建的副产品,而是VB是VBA出现的副产品。
本文将阐明 Visual Basic 的两个主要部分是什么,每个部分背后的思想是什么,以及每个部分背后的人员。
正如您可能已经从上面猜到的那样,有两个主要组成部分。它们是 Ruby 和 EB。也许最恰当的说法是,Visual Basic 是 Ruby 和 EB 结合的结果,这两种技术彼此独立出现,并且非常契合。
Ruby
在我们进一步讨论之前,需要注意一个非常重要的事项:在下文中,“Ruby”一词与 Ruby 编程语言和 Ruby on Rails 框架无关。 毕竟,“红宝石”这个词只是翻译为“红宝石”。
(照片:Alan Couper)
如果你曾经搜索过关于Visual Basic是如何形成的信息,你可能在维基百科或其他地方遇到过这样的词:
1991 年 5 月 – Visual Basic 1.0 for Microsoft Windows 发布。该语言基于QBasic语法,后来使该语言大受欢迎的创新是语言和图形界面之间的连接原则。这个原理是由Alan Cooper开发的,并在Tripod原型(也称为Ruby)中实现。第一个 Visual Basic 是一个解释器。
从关于 Alan Cooper 本人的文章中,您可以了解到他尤其被称为“Visual Basic 之父”。文章的英文版信息量更大一些。
事实上,Alan Cooper 没有在 Microsoft 工作,也不是 VB 开发团队的一员——他的优点是不同的。Alan Cooper 提出了轻松创建视觉外壳的概念,并与同事一起创建了一个用于创建视觉外壳的工具。让我提醒您,我们谈论的是 80 年代,以及带有图形界面的操作系统刚刚普及的时代,而 DOS 和其他带有文本界面的操作系统是主流。
Alan Cooper 的团队制作的产品叫做 Ruby,最有趣的是它不是程序员的工具——它是没有特殊技能的普通用户的工具,根据 Cooper 的说法,这使他们能够快速塑造一个视觉外壳,从而促进一些工作。哦,这是浪漫主义者的时代,他们相信,如果你给人们一台电脑,每个人都会用自己的双手学习和编写程序,让电脑完全按照主人的要求去做。Ruby 既不是一种编程语言,也不是现代意义上的集成开发环境 (IDE)。
根据 Cooper 的说法,当他看到 Windows 1.0 时,他意识到该平台拥有巨大的未来。他被两件事所震撼:图形界面和DLL概念,它允许动态配置的可扩展系统,但与此同时,当时的Windows shell(资源管理器和桌面在现代意义上还不存在)在他看来简直太糟糕了。就在那时,他决定为 Windows 编写完美的 shell。Alan Cooper 与他的客户交谈并试图了解理想的外壳应该是什么,他意识到没有完美的外壳。并且有必要为用户提供一种工具,使他们能够每个人都根据自己的需求和任务构建自己的外壳,而不是试图向他们推送一些理想的外壳,同时试图向他们解释它的完美之处。这个自定义皮肤构建器最初被称为 Tripod,但后来更名为 Ruby,因为“Tripod”这个名字被很多人使用。
后来,艾伦·库珀(Alan Cooper)向比尔·盖茨(Bill Gates)展示了他的发展。盖茨喜欢这个概念,即用户可以绘制可视化控件,将它们放置在桌面上的任何位置,拖放,调整大小,最重要的是,将一些操作与控件相关联,因此他决定购买Ruby。从此,Microsoft成为了Ruby的拥有者,并决定了产品未来的命运。
Microsoft决定改变 Ruby 的本质:离开易于构建可视化界面的概念(“在必要时绘制一个按钮并快速将一些动作链接到它”),从创建可视化界面的工具(在现有程序上)的目标受众由普通用户组成,将其转变为创建具有可视化界面的新程序的工具,其目标受众将只是程序员。让我提醒你,最初 Ruby 背后没有编程语言,除了视觉设计的原则(只有一个简单的指令系统,其集合是可扩展的,因为DLL 以及调色板中的一组控件(Cooper 称它们为“gizmo”,保留在 VB6 中),它也通过第三方 DLL 进行了扩展),并且有必要决定哪种语言将构成新工具的基础。但是Microsoft已经有了QBASIC,你可以准确地猜到比尔盖茨在决定购买Ruby这样有前途的资产时,他的脑海中诞生了什么计划。
在历史的这一点上,构建可视化界面的概念和机制,完全没有任何编程语言,必须与一种编程语言和确保其执行的机制相遇,完全没有可视化组件。
EB:你有没有看过VB运行时导出了多少个不同的未记录的函数?
您一定听说过 EbExecuteLine 函数,它允许您解释和执行任意代码行(尽管仅在 IDE 下工作时)。你有没有想过所有这些函数名称中的“Eb”前缀是什么意思?它代表什么?
现在我们将处理这个问题。
我不确定两种可能的解密的两个版本中哪个更正确,但显然这两个版本都与事实相去不远。让我们从第一个版本开始,转向臭名昭著的乔尔·斯波尔斯基(Joel Spolsky)的一篇文章。
这篇文章被称为“我的第一个 BillG 评论”。
简要复述一下这个故事:
- 1991 年夏天,Joel 在 Microsoft 的 Excel 开发部门找到了一份工作。当时Excel的实际问题之一是Excel有自己糟糕的宏编程语言,它没有全局变量和局部变量,没有过程,有goto,但没有标签。该语言没有自己的名称,通常称为“Excel 宏”。
- 乔尔的任务就是解决这个问题。有一种观点认为,这个问题的解决方案必须与基本语言有关。在另一个部门(作为Microsoft的一部分)已经开发了一个代号为“Silver”的面向对象的BASIC。白银团队的经理只看到了他的技术的一个应用程序——Excel。Joel 说服了 BASIC 团队的人,Excel 团队需要类似 BASIC for Excel 的东西。同时,他坚持在语言中添加 4 个功能:
- 添加可以存储任何其他类型的值的 Variant 变量,否则将无法将 Excel 表格单元格的值存储在变量中(至少不能不求助于“选择大小写”)。
- 添加稍后的链接(通过 IDispatch),因为原始的 Silver 体系结构需要对类型系统有深入的了解,而为 Excel 编写宏的人不想理解。
- 添加从 csh 借来的 For Each 构造。
- 添加结构…End With,借自 Pascal。
- 在那之后,乔尔坐下来写了一份未来语言 Excel Basic 的规范,大约花了 500 页,然后发送给比尔盖茨进行审查/审查。文章的其余部分描述了比尔·盖茨(Bill Gates)随后的会议,在会上,他根据盖茨在阅读规范时留下的旁注向乔尔提出了问题。
- 文章的最后一部分说,随着时间的流逝,事情取得了很大的进展,Excel Basic 变成了 Visual Basic for Applications,盖茨曾经记得在 Excel 团队中聘请那个做这一切的聪明经理是多么困难。
因此,正如您从本文的文本中可以理解的那样,在某些时候,需要用更高级的东西替换 Excel 中糟糕的宏语言,这导致将赌注押在类似 BASIC 的语言上,并基于另一个部门可用的开发来创建面向对象的类 BASIC 语言 Excel Basic(缩写为 EB) 是一种面向对象的通用语言,几乎可以自动执行任何操作,因此在适用性方面迅速超越了 Excel。由于该语言不仅允许您为 Excel 编写宏/扩展/自动处理,而且允许您为任何内容编写宏/扩展/自动处理,因此该技术不仅开始用于 Word/Access——Microsoft 设法将其出售给 AutoCAD、SolidWorkds、Corel Draw和 ArcGIS 的创建者。可以理解的是,具有如此广泛范围的技术不能再称为 Excel Basic,而是更名为 Visual Basic for Applications,特别是因为除了 Office 和第三方程序之外,该技术还成为所谓的 Visual Basic 的一个组成部分.与此同时,缩写“EB”在许多与技术相关的功能和结构的名称中扎根,并一直保留到今天。
EB 名称的第二个版本不是 Excel Basic,而是 Embedded Basic。根据 Scott Ferguson(他开玩笑地称自己为“Visual Basic 之母”)的说法,在 80 年代和 90 年代之交,Microsoft正在开发 Omega DBMS,这个项目最终被放弃了。Omega DBMS包括嵌入式基本(EB)引擎。开发是在一个名为“商业编程语言部门”的部门进行的,同时在QuickBASIC上工作。但是“商业编程语言”部门的主要资源集中在创建一种新的、面向对象的、面向 Windows 的类似 Windows 的基本编程语言上,称为 Silver(我们已经在 Joel Spolsky 的故事中看到过这个名字和这个产品)。有一次,比尔·盖茨(Bill Gates)向“商业编程语言”部门发送了一个请求,询问是否可以以某种方式跨越Ruby和EB。John Fine(当时的项目经理)和 Scott Ferguson 的任务是回应这一请求。
创建了一个团队,将他们的 EB 与刚刚从侧面购买的 Ruby 进行了非常困难的集成:
(照片中的两个人,他们的脸被涂上了油漆,被外部摄影师邀请来改善框架的构图,与 VB 的开发无关)
由 EB 和 Ruby 合并而诞生的新产品被称为 Thunder斯科特·弗格森(Scott Ferguson)回忆说,早在1989年1月,约翰·费恩(John Fine)就写了一份名为“Visual BASIC”的编程语言提案(可能是写给他的上级,也许是盖茨本人)。 这早在 Microsoft 推出 Ruby 之前就已经存在了。 比雷霆发布之前晚得多这个名字从遗忘中复活了关于许多其他被认为是产品正式名称的候选名称。而且,事实上,许多人不喜欢它。当时大多数人都喜欢“雷霆”这个名字,口号是“破解窗户的力量”。
无论哪种方式,EB 代表 Excel Basic 还是 Embedded Basic 都无关紧要。从 Joel 对 EB 中引入 4 项重要创新的贡献来看,这些创新至今仍保留在 VB/VBA 中,他对历史的展望以及对 VB 和 VBA 发展的贡献也应该被考虑在内。
显然,有Silver技术和EB引擎,最初是为Omega DBMS创建的。
EB 本身并非没有 Joel 的参与,它成为了 Excel 的一部分,并成为现在所说的 VBA。
EB 与 Cooper 的 Ruby 合并,受到 Silver 思想的影响,成为现在所谓的 VB。
包含 EB 的 Omega 项目大概转世为 Access/MS Jet,其中 EB 仍然是其中的重要组成部分。
直到
产品的最新版本 VB6,Ruby 和 EB 之间的界限还没有消失,两个组件也没有合并到无法区分的地步。它们之间仍然有明确的界限,每个组成部分都从事自己的业务,可以说有自己的责任领域和任务领域需要解决。
即使在源代码级别也保持分离(可以从带有调试符号的文件中获取有关编译 VB 的源代码的信息)。就源代码集而言,VB6 由两个文件夹组成:ruby/ 和 vbadev/
第一个包含所有 Ruby 源代码,第二个包含所有 EB 源代码(正如我们从 Joel 的文章中知道的那样,EB 在某个时候重命名为 VBA)。对于 Ruby 中的许多函数和变量,我们将找到 Rby 前缀作为前缀,对于许多函数、变量和 EB 结构,我们将看到 Eb 前缀。
EB – 它包括什么,它做什么以及它负责什么:
- EB/VBA 基本上被设计为一种可以附加到任何事物的技术——任何外部应用程序(术语“主机”用于此类应用程序)。EB/VBA 连接到主机后,允许您编写可以与主机交互的代码,管理主机的对象模型,这最终可以根据需要扩展主机的逻辑,并为 EB/VBA 附加到的任何主机应用程序编写自动化。
- EB/VBA 与主机无关 — 主机依赖于 EB/VBA,并且 EB/VBA 可以“拧”到任何事物上。
EB + Excel 在 Excel 中为我们提供了 VBA。
EB + Word 在 Word 中为我们提供了 VBA。
EB + AutoCAD在AutoCAD中为我们提供了VBA。
EB + Ruby 为我们提供了我们所知道的“独立 VB”(VB1-VB6)。
也就是说,Ruby 只是 EB 主机的一个特例。Ruby 离不开 EB,但 EB 可以和任何其他主机一起生活。 - 具有语法突出显示、自动完成和 IntelliSense 的代码编辑器是 EB/VBA 的一部分。我们谈论的是文本字段本身,其中编写了代码,不包括工具栏、工具栏、菜单。正是由于这个原因,代码编辑器在 VBA 和 VB 中是相同的。
- 运行 P 代码的虚拟机是 EB/VBA 的一部分。
- 使用即时编译原则解析 VB 代码并将其转换为 P 代码的机制是 EB/VBA 的一部分。因此,该语言的语法也是 EB 的一部分,与 Ruby 无关,因此,在 EB 附加的所有主机中,语言都是相同的,具有相同的语法规则和功能(例如,Not Not Arr 错误将无处不在)。
- 一组基本类型和一组语言支持的运算符(And、Xor、Like 和 &)是 EB/VBA 的一部分,因此无论 EB/VBA 连接到哪个主机,它们在任何地方都是相同的。如果您是主机开发人员,并且可以完全控制主机的源代码,但 EB 对您来说是一个黑匣子,那么您就无法在代码中获得对新运算符的支持(例如,一开始就不存在的按位移运算符)。
- 错误处理的概念是 EB/VBA 的一部分,因此无论 EB/VBA 被搞砸了,一切都是一样的。
- 一切都被划分为项目,项目由模块(更准确地说,项目项)组成的概念源于 EB/VBA。同时,EB 对任何表单和 UserControls 一无所知——从 EB 的角度来看,模块只有两种类型(常规和对象)。主机可以为对象模块设置自己的子视图。在 VB6 中,这些是类、窗体、用户控件。在 Excel 中,这些是类、用户窗体、工作表和工作簿。其他一些主机可能有自己的模块子类型。但是项目和模块的一般概念将存在于任何主机中。
- 链接对第三方类型库的引用的概念是 EB/VBA 机制的一个功能,因此它存在于 VB 和所有 VBA 应用程序中。连接到 EB 内部项目的 TLB 的链接称为 EBREF,并由同名结构描述。
- 所有被大多数人称为“运行时函数”的函数,如 MsgBox、InputBox、Rnd、Beep、CreateObject、DateDiff、RGB、StrReverse、MkDir,都是 EB/VBA 的一部分,因此所有这些函数不仅必须存在于纯 VB 中,而且必须存在于 VBA 中:Excel、Word、AutoCAD 和任何其他主机。
- Collection 和 ErrObject 类是 EB/VBA 的一部分,同样可以在纯 VB 和 Microsoft Office 应用程序和其他主机中找到。
- 未记录的、因此鲜为人知的机制(如表达式服务器和 VBA 事件监控系统)也是 EB 的一部分。
- 在程序执行过程中,任何与用户界面和任何视觉表现有关的内容都不是 EB 的一部分。例如,MsgBox 函数是 EB (VBA) 的一部分,它显示一个包含消息的对话框,但不会直接显示窗口 – EB 不知道消息应该如何显示或通过什么方式显示。相反,EB 调用其主机并调用主机的特殊回调函数,该函数负责显示消息的可视部分。EB 和主机之间有一个接口,例如主机提供的回调指针数组。当主机初始化 EB 时,它会从 EB 调用 EbInitHost 函数并将数组传递给 EB。EB 会记住指向此数组的指针,并在需要显示消息时获取数组的相应元素(此地址对应于回调函数)并调用所需的函数。正是主机代码决定了消息的显示方式,它是否是一个窗口,它将是什么样的窗口,以及它将具有什么样的外观。在这方面,EB 的用途非常广泛,例如,EB 可以托管使用 DirectX 的全屏游戏。而在这个游戏中,联系 MsgBox 不会导致出现通常的 Windows 对话框,这将破坏全屏模式 – 游戏主机为显示消息而实现的回调函数将以游戏风格显示消息,该消息将通过使用 DirectX 渲染来显示,就像所有其他游戏 UI 一样。
Ruby — 它包含什么,它做什么,以及它负责什么:
- 首先,Ruby 不知道(也不在乎)管理基础设施的代码背后是什么语言——Ruby 提供的代码。在VB的情况下,EB与Ruby结合使用,但纯粹是假设的,可能有裸露的C / C++代码,或者一些脚本引擎,或者像Scratch这样的可视化编程系统,其中代码不是编写的,而是以流程图和图表的形式绘制的。顺便说一句,根据 Alan Cooper 最初的想法,这正是 Ruby 的工作方式:当用户绘制一对小玩意儿时,比如一个按钮和一个叶子框,然后为了让它成为当点击按钮时,用户直接用鼠标画一个箭头,从第一个小玩意儿的“click”事件到第二个小玩意儿的“hide”方法。所以。。。
- VB 的所有内置控件(如 CommandButton、ListBox、Drive、Circle、PictureBox 和 ScrollBar)都是 Ruby 的一部分。
- App 对象、Clipboard、Forms 集合、Printers、Screen 对象、Load 和 Unload 方法以及 LoadPicture/SavePicture 方法都是 Ruby 的一部分。因此,一旦在 Excel 中打开 VBA,您将无法在那里编写 App.Path 或 Screen.ActiveForm — 那里根本没有 App 或 Screen,因为它们是 Ruby 的一部分,而不是 EB。
- 创建窗口的表单机制是 Ruby。
- 所有窗口消息处理、过滤、转发和将窗口消息转换为控制事件都是 Ruby。
- 与开发环境 (IDE) 以及如何在设计时绘制形状相关的重要部分是 Ruby。例如,项目树、组件调色板、属性面板、项目属性对话框、环境对话框、支持可插拔加载项的机制——所有这些都是 Ruby。
- 运行独立EXE文件所需的所有支持机制,以及通过DLL / OCX文件的形成编译的项目的工作,以及ActiveX EXE项目 – 所有这些都是Ruby。例如,任何 ActiveX DLL 都必须具有 DllGetClassObject 函数,该函数返回所请求类的类工厂。DllGetClassObject 和类工厂都是在属于 Ruby 的源文件中实现的。
- 与 OLE、DDE 和数据绑定机制相关的所有内容(例如,当窗体上的控件(例如文本字段)绑定到记录集的字段并在浏览记录集中的行时更改自身,并且更改控件中的值会导致数据库中值的更改 — 所有这些都不需要 VB 程序员编写额外的值,只需在窗体控件和数据库之间建立连接) — 所有这些都是 Ruby。
这就是师。如果我们假设您手中有完整的 VB 源代码,并且您需要修复按钮行为中的某些内容或向表单添加新属性,请转到 Ruby 源代码。如果要修复内置 Collection 类中的某些内容,或者想要向 VB 添加新的运算符,请转到 EB 源代码。
Ruby 和 EB 的划分不仅在源代码级别可见。如果我们转到 Project→References,我们将看到几个无法禁用的附加类型库。其中一个对应于 EB 贡献的所有内容,另外两个对应于 Ruby 贡献的所有内容:
EB/VBA 有自己的类型库,您可以在其中找到所有内置的运行时函数,以及仅有的两个类,Collection 和 ErrObject:
如果我们在 Excel 中打开 Visual Basic,我们将在“引用”和“对象浏览器”中看到相同的类型库,并且所有函数都已到位。
Ruby 有自己的类型库,您可以在其中找到所有内置控件和对象,例如 App、Printers、Screen:
Anatomy VB6.EXE、VBA6.DLL
和 MSVBVM60.DLL 每个人都知道,编译的 VB 项目将不可避免地依赖于MSVBVM60.DLL— 无论此库的名称如何(运行时和 VB 虚拟机)。只要项目作为源代码存在并在 IDE 下进行调试,其工作就由 IDE 本身提供,它主要由两个二进制文件组成:
- VB6.EXE
- VBA6.DLL(VB6.EXE取决于它)
一个对某些人来说似乎令人惊讶的事实:馅料msvbvm60.dll一半馅料VB6.EXE,一半馅料VBA6.DLL。
事实上,VB6.EXE 是编译 Ruby 源代码的结果,VBA6.DLL 是编译 EB 源代码的结果。
运行时MSVBVM60.DLL只包含大约一半的 Ruby 和一半的 EB。
两组源代码(ruby/ 和 vbadev/)体现了本产品的两个主要组件,由于编译和链接了不同的键和选项,总共提供了 3 个可执行文件。
也就是说,没有“MSVBVM60.DLL源”和“VB IDE 源”这样的东西——两者都是从相同的源编译和构建的!但是使用不同的编译选项和键,使用不同的条件编译标志。
构建 IDE (VB6.EXE + VBA6.DLL) 的过程如下:
构建运行时库的过程MSVBVM60.DLL几乎相同的:将相同的源文件(使用略有不同的编译键)编译为目标文件 (obj),然后将整个内容链接到单个生成的 DLL 文件:
正如人类的遗传密码与黑猩猩的遗传密码有98%相同一样,msvbvm60.dll中的绝大多数二进制密码都重复了vb6.exe或vba6.dll的密码。几乎任何属于 msvbvm60.dll 的过程要么是 Ruby 的一部分,要么是 EB 的一部分,因此在vb6.exe或vba6.dll中都可以发现没有变化或略有改变。
反之则不然:代码 vb6.exe (1.80 MB) 和 vba6.dll (1.61 MB) 的总大小大于msvbvm60.dll的大小 (1.32 MB)。
显然,Ruby 包含实现表单编辑器或项目属性对话框的代码——所有这些都进入了vb6.exe,但不会进入msvbvm60.dll(那里不需要)。
显然,EB 包含将 VB 代码解析、解析和编译为 P 代码的代码——所有这些代码都进入vba6.dll,但不会进入msvbvm60.dll(那里不需要)。
如果我们做一些简化,并且不打算完全保持规模,下图完美地说明了构成 IDE(环境)和运行时可执行文件的可执行文件实际上是如何由公共代码
组成的:上面已经有不完整但足够多的列表,这些内容是 Ruby 的一部分,也是 EB 的一部分.如果我们进一步简化它,丢弃不必要的组件,只留下 VB 中最出色和最常被记住的组件,那么我们可以将它们放在这个插图上。我想再说一遍:这是一个基于非常简化的文本的强大简化图像。它的目的不是创建构成 Ruby 和 EB 的子组件的完整列表。一个完整的列表不适合这样的小图片,图片必须至少大 20 倍。目标是简单地看插图,理解和感受这个想法,分离的原则。大致了解哪些子组件(负责哪些事情)是 Ruby 的一部分,哪些是 EB 的一部分,以及这些子组件是如何分布在可执行文件(VB6.EXE、VBA6.DLL 和 MSVBVM60.DLL)中的。在下面的文章中,我们将更详细地讨论 EB 和 Ruby 的组成,更全面地考虑构成一个可行的 VB IDE 的组件集(毕竟除了 VB6.EXE 和 VBA6.DLL,还有 LINK.EXE、C2.EXE MSO98RT.DLL )。
大约一年前,我写了这篇文章的文字。
VB创建者专门为本文翻译了其他文章的两个版本:
- 艾伦·库珀。为什么我被称为“Visual Basic 之父”
- 斯科特·弗格森。雷。。。Visual Basic 的诞生
我强烈建议在阅读本文后阅读这两个翻译,以便深入了解事件参与者对同一事物的看法。
Old_Maple写道:
P.s. 这个问题纯粹是理论上的:是否可以在不求助于其他 x62 或 x64 编程语言的情况下用 VB6 编写 VBx64?
在回答这个问题之前,我想再问一个问题。
我们所说的 64 位 VB 是什么意思?我们想从 64 位 VB 中得到什么?
64 位 VB 主要是 64 位二进制文件(EXE 和 DLL)的结果吗?
如果是这样,我们为什么需要它?32 位二进制文件已在 64 位操作系统下成功启动。但反之则行不通:64 位二进制文件不会在 32 位操作系统下启动。因此,在这方面,游戏得不偿失,最终并不能证明手段的合理性,32 位二进制文件变得更加通用。
或者,也许我们想以巨大的地址空间的形式利用 64 位架构,不受标称 4G 和实际 2G(或 /3GB 模式下的 3G)地址的限制?
还是我们主要对 64 位算术和毫无问题地操纵大量数字的能力感兴趣?
在这两种情况下,由于这些创新而自动产生的最严重的问题是:如何处理VB型系统?
准备好在具有 64 位虚拟地址空间地址范围的 64 位环境中自动意味着需要切换到 64 位指针并增加所有指针类型的大小。As String 和 As Object 类型的大小将从 4 个字节增加到 8 个字节。
在某种程度上,这已经破坏了现有 VB 代码的向后兼容性和性能,这些代码依赖于这些类型的大小为 4 字节的事实,并使用 CopyMemory、GetMem4、PutMem4 处理此类变量。最阴险的是,如果新 64 位 VB 下的旧代码只是拒绝启动和编译,会以红色突出显示,那就太好了,但在我们的例子中,它会爆炸式地编译和运行,只是它会以不可预测的方式工作——并且有一定程度的概率它甚至可能继续正常工作,但这将是一个运气问题。而且并不是代码中所有的执行分支总是被执行,代码中的某些分支只在极少数情况下被执行,所以找到这样的地方不会那么容易。
更改 As String、As Object 类型的大小也很可怕,因为它会自动增加具有类似类型字段的结构(用户 Defiend 类型)的大小,并且所有其他字段都会被置换。
如果我们有一个结构,我们必须传递给某个库的某个 API 函数,或者我们必须以二进制形式将其写入文件,那么当类型大小调整时,我们将打破代码的旧良好行为。这可能会被证明是一个完全出乎意料且不明显的故障。
到目前为止,我们同意作为具有 64 位寻址的 64 位进程存在,但假装我们仍然像以前一样拥有整数类型。但是我们不能保持整数类型原样。
毕竟,我们有函数 VarPtr、StrPtr、ObjPtr,它们都具有返回类型 Long。如果我们出于向后兼容目的将 Long 保留为 4 个字节,那么在新环境中,我们会得到不可行的 VarPtr/StrPtr/ObjPtr 函数,因为现在并非每个新大小的地址都适合旧地址的 Long 类型大小。
如果我们将 Long 类型增加到 64 位的大小,那么我们就会破坏与现有 VB 代码的迷人卷的向后兼容性。特别是,所有将某些数据写入文件或相反从文件中加载它们的代码都会中断,因为在编写结构时
Type FOO
xxx as long
yyy as long
zzz as long
End Type
不是 12 个字节,而是 24 个字节将读取/写入文件或从文件中读取。
因此,默认情况下,更改 Long 类型的大小显然是一个坏主意。
然后,您需要为 64 位数字输入新类型。龙64?还是龙龙?
在这种情况下,VarPtr 的返回类型必须为 Long64 而不是 Long,以便整个潜在地址范围都适合它。但是,完全消除旧的 VarPtr/StrPtr/ObjPtr 是合乎逻辑的,取而代之的是引入返回类型为 Long64 的 VarPtr64、StrPtr64、ObjPtr64,以便故意破坏表单的旧代码
Dim address As Long
address = VarPtr(foo)
这样它就会停止启动。因为只有这样才能迫使一个人到达这些行并将 VarPtr 更改为 VarPtr64,并将 Long 声明变量为 Long64。否则,从未重命名的 VarPtr 返回的返回将被分配给 Long 类型的变量,这可能会导致 Overflow 错误,该错误只会在运行时(并非总是)捕获,而不是在编译阶段捕获。
好的,我们正在引入像 Long64 这样的新类型。
但有一个问题。更准确地说,不仅仅是一个问题,而是一整组问题,同样与兼容性有关。
这不仅限于 VB,而是来自 COM 和 OLE 自动化的东西——它允许 VB 应用程序与非 VB 应用程序进行交互,反之亦然。用 VB 编写的对象可以从 C++ 应用程序使用,您也可以从 VBScript 轻松使用它,它根本没有类型。或者,您可以从 PHP 脚本中使用用 VB 编写的对象,因为 PHP 有一个扩展可以处理 COM 对象,如果 PHP 环境在 Windows 上运行并启用了 COM 扩展,那么一切都会解决。虽然PHP也没有类型。
由于 Variant 类型,它可以容纳 VB6 类型系统中的任何类型的任何值(甚至更多:因为 VB 没有 Decimal 这样的类型,但 Variant 有)。
毕竟,在 VB 中,我们可以在不指定类型的情况下声明一个变量,然后它将是 Variant 类型(如果模块中没有 DefNg 类型的功能),我们可以为任何具有 type 的变量赋值
Dim x
Dim y as Long
Dim z As Double
Dim k As Date
Dim j As String
x = y
x = z
x = k
x = j
但是,如果我们在 VB 类型系统中引入全新的类型,那么 Variant 不支持这些新类型呢?
Variant 类型甚至支持什么?这是个好问题。因为官方支持两组 Variant 子类型。
一个小子集对应于 VB 以内置类型形式以及 Decimal 类型具有的所有类型。此类型子集也称为与 OLE 自动化兼容的类型集。因此,此子集没有体现新引入的 Long64 的类型。
还有另一组:更广泛的一组,为 COM 技术开发。 它有一个半电流类型来表示 Long64。但是,如果这样的 VARIANT 值“浮动”到旧的 VB6 代码或 VBScript,则一切都会中断,因为此类值不受官方支持。
或者更确切地说,它甚至有点复杂:VARIANT 容器基本上能够存储 Long64 类型的值,但将这些值转换为接穗类型的变量(例如 Long)可能会产生具有一定概率的溢出错误,另一方面,使用此类值的操作(例如将一个 Variant 添加到另一个 Variant)可以完美工作或无法正常工作,因为对 Variant 的操作不是由 VB 本身执行的(或VBScript,或者其他什么),但系统库OLEAUT32.DLL,它在不同版本的操作系统中执行此操作的方式不同。这是关于这个话题的一个非常有趣的话题。
所以这是一个非常复杂的话题,也是一个尖锐的问题。应该非常谨慎地对待它。
一方面,我们希望 VB 中出现新类型:无符号类型和 64 位数字类型。另一方面,Variant 类型阻碍了我们在近 30 年前宣布“受支持”的那些类型。其他类型得到半官方支持:在实践中,它们有效,但在法律上我们进入了灰色地带,如果某些东西突然开始失败,则不清楚谁应该为错误的行为负责,谁负责修复他们的组件。
现在让我们回到最初的问题:
Old_Maple写道:
是否可以在不求助于其他 x32 或 x64 编程语言的情况下用 VB64 编写 VB64?
好吧,首先,没有“x32 编程语言”或“x64 编程语言”这样的东西。
这完全取决于我们的要求或我们对假设的新 VB64 的期望。它是否应该在架构、行为和运营模型上与 VB6.0 有些相同和相似?
VB6 目前的架构是这样的,只要项目没有编译,在开发环境下调试时,所有的代码执行都在开发环境进程中进行。一个项目没有被编译成二进制文件,而是启动执行,就像一个子宫里的孩子。
从这个意义上说,如果我们想象一个假设的 VB64,那么调试模式下的代码应该在 64 位进程中工作,这意味着 IDE 可执行文件应该是 64 位可执行文件。现有的 VB6 无法生成 64 位可执行文件。而基于这个逻辑,不可能在VB6上写VB64。
另一件事是,如果我们不给自己设定重复与 VB6 相同的架构解决方案的要求。如果项目的调试,它在项目的调试模式下启动,不必在开发环境的父进程中作为P代码的执行来执行,如果我们允许自己从32位VB64 IDE进程中生成一个新的64位子进程来调试VB64项目的运行,那么我们就没有上述限制,我们可以在VB6中毫无限制地编写这样的VB64 IDE。另一个问题是,这将是一个方便和最佳的选择,但这个问题纯粹是理论上的。
原文链接:VBStreets 会议 • 查看主题 – § 10.Ruby + EB = Visual Basic
Views: 112