ActiveX / COM / VB6 企业项目的构建流程
我们使用微软的ActiveX/COM (VB6)技术开发了一个软件系统。 去年,我对自动化构建流程和整个 SCM 越来越感兴趣。 我深入地搜索了网络的大部分内容,以获取有关如何使用基于 COM 的软件系统进行 scm 的最佳实践的信息。
COM 的“问题”是,引用组件通过唯一的接口 id 保存引用。 当您重新编译引用的组件时,id 可能会更改并且引用不再有效。 这里的主要问题是 iid 被编译到二进制文件中。 因此,当我不想将编译后的文件签入版本控制时,每个开发人员都必须编译他/她自己的版本并获取其他 id。
当我想在干净的构建机器上检查源代码来编译系统时,这是不可能的,因为所有引用都是无效的(没有二进制文件,没有接口 ID)。
我只是想知道,是否有一些最佳实践,如何为 COM 项目(VB6)设置自动构建系统?
编辑: 是的,我知道兼容性设置。 但以场景为例,我想在没有任何二进制文件的干净构建机器上构建整个系统。 当您说一个项目是二进制兼容时,您必须提供与该项目兼容的二进制文件。
我想我必须编写一个自定义构建工具,它可以在编译项目之前和之后修改项目文件中的引用和兼容性设置。
因为 VB6 / COM 是一种非常广泛传播的技术,所以我只是想必须有一个现成的解决方案。
我们通常以二进制兼容性进行编译。 当我们修改组件的公共接口时,我们会使用项目兼容性进行编译。 但是,当您更改许多其他组件使用的基本组件的接口时,您必须手动将所有引用项目更改为项目兼容性,重新编译它们并更改回二进制兼容性。 这就是我想要自动化的主要流程。
We have developed a software system using ActiveX/COM (VB6) technology from microsoft. In the last year, i get more and more interested in automated build processes and SCM at a whole. I intensively searched big parts of the web for information about best practices how to do scm with COM based software systems.
The "problem" with COM is, that a referencing component holds the reference by an unique interface id. When you recompile the referenced component, the id may change and the reference isn't valid any more. The main problem here is, that the iid is compiled into the binary. So when i don't want to check in the compiled files into version control, every developer has to compile his/her own versions and gets other ids.
When i want to check out the source on a clean build machine to compile the system, its just impossible, because all the references are invalid (no binary files, no interface ids).
Im just wondering, if there are some best practices floating around, how to set up an automated build sytem for COM projects (VB6)?
Edit:
Yes, im aware of the compatibility settings. But take the scenario, where i want to build the wohle system on a clean build machine without any binaries.
When you say a project is binary compatible you have to provide the binary with which the project is compatible.
I think i have to write a custom build tool, which modifies references and compatibility settings in the project files before and after compiling the projects.
Because VB6 / COM is a really wide spread technology, i was just thinking that there has to be a ready to use solution.
We normally compile with binary compatibility. When we modify the public interface, of a component, we compile with project compatibility.
But when you change the interface of a basic component which is used by a lot of other components, you have to manually change all referencing project to project compatibility, recompile them and change back to binary compatibility.
Thats the main process i want to automate.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以通过将项目的兼容性设置从“无兼容性”更改为“二进制兼容性”来告诉 VB6 重用 GUID(IID、CLSID、LIBID 等)。 您可以在“项目”->“您的项目”属性下找到这些设置。 兼容性设置位于“项目属性”窗口的“组件”选项卡上。 有以下三种选择:
以下是 MSDN 关于它们的说明:
听起来您当前正在使用无兼容性进行编译。 正如 MSDN 文章所述,您需要使用二进制兼容性来保持组件的新版本与旧版本兼容。 您现在可以通过执行以下操作来完成此操作:
在无兼容性的情况下编译每个项目一次
保存这些 将“干净”版本保存到进行构建的人员可以轻松访问的文件夹,例如网络共享,或者将它们放入源代码管理中。
返回并将所有项目更改为“二进制兼容性”,并将“兼容文件”指向您刚刚在网络/源代码管理中保存的相应版本(不要将兼容文件指向您之前保存的相同路径)兼容文件应该是原始组件的单独副本,不会更改。它的存在只是为了在重新编译时 VB 可以将 ID 从该文件复制到您的项目中。
每次重新编译项目时,它们都会重用组件的兼容(原始)版本中的 GUID。
编辑:正如乔在评论中提到的,您还必须认识到您的类接口何时发生了更改(即,当接口发生足够大的变化以至于您可以更长地保持与以前版本的二进制兼容性时)。 发生这种情况时,您希望与组件的先前版本彻底决裂:重新编译新的“干净”版本(即不兼容)并在将来的构建中使用该新版本作为兼容文件。 但是,请务必注意,只有当类接口(属性和方法)发生更改时,您才应该重新开始。 事实上,当项目不再与组件的先前版本兼容时,VB 会警告您。
如果你想生活在边缘......
在我工作的地方,我们倾向于在大多数项目中(ab)使用“不兼容性”,即使这并不是真正正确的做事方式(您应该使用二进制兼容性)。 在我们公司,这是一种惰性,因为我们有一个自动构建工具,可以为我们编译所有项目,该工具的主要功能之一是可以自动修复项目之间损坏的项目引用。 由于构建工具为我们解决了这个问题,因此使用二进制兼容性的动力较少。
为什么二进制兼容性更好(或者...为什么你不应该做我们所做的事情)
二进制兼容性通常是更好选择的几个原因:
Microsoft 是这样说的
如果您的所有组件都与以前版本的软件二进制兼容,您可以轻松地重新编译单个组件,并且将其重新分发给您的客户。 这使得错误修复/补丁更容易部署。 如果您在项目中使用“No Compatibility”,则每次需要发布一个小补丁时,您都必须重新编译并重新分发整个应用程序,因为较新的组件(可能)无法与较旧的组件一起使用。
您正在尽自己的一份力量来维护 COM 标准:在 COM 中,类 ID 和接口 ID 应该唯一地标识类或接口。 如果您的类和/或接口在构建之间没有更改,则没有理由为这些类和接口生成新的 ID(事实上,同一个类将具有多个 ID)。 二进制兼容性允许您在各个版本中维护相同的 ID,这意味着您是一个好公民并遵循 COM 约定。
减少注册表噪音。 如果您总是向与旧版本不二进制兼容的客户部署新组件,则每个新版本都会向注册表添加新信息。 除其他事项外,每个新接口和类 ID 都必须注册。 如果您保持所有内容二进制兼容,那么安装程序只需将注册表项添加到一个位置,因为您的类 ID 和接口 ID 不会更改。
如果您要公开其他第三方应用程序正在使用的公共 API 或组件,您肯定会希望使用二进制兼容性,这样就不会破坏依赖于您的代码的第三方软件。
You can tell VB6 to reuse GUID's (IID's CLSID's LIBID's etc.) by changing the compatbility setting of the project to from "No Compatbility" to "Binary Compatibility". You can find these settings under Project->Your-Project Properties. The compatibility setting is on the Component tab of the Project Properties window. There are three choices:
Here's what MSDN says about them:
It sounds like you are currently compiling with No Compatibility. As the MSDN article states, you need to use Binary Compatibility to keep newer versions of your components compatible with older versions. You can do this now by doing the following:
Compile each project once with No Compatibility
Save these "clean" versions to a folder that people doing the builds can easily access, such as network share, or, put them in source control.
Go back and change all the projects to "Binary Compatibility" and point the "Compatible File" to the corresponding version that you just saved on the network/in source control (do not point the compatible file to the same path that you are compiling the project to. The compatible file should be a separate copy of the original component that won't change. It only exists so that VB can copy the ID's from that file into your project when you recompile it).
Every time you recompile your projects, they will reuse the GUID's from the compatible (original) versions of the components.
EDIT: As Joe mentioned in the comments, you also have to recognize when your class interfaces have changed (that is, when an interface changes enough that you can longer maintain binary compatibility with the previous versions). When this occurs, you want to make a clean break from the previous versions of the components: recompile a new "clean" version (i.e. with No Compatibility) and use that new version as your compatible file in future builds. However, it's important to note you should only start over again when your class interfaces (properties and methods) change. In fact, VB will warn you when a project is no longer compatible with the previous version of the component.
If you want to live on the edge...
Where I work, we tend to (ab)use No Compatibility on most of our projects, even though it's not really the correct way to do things (you should use Binary Compatibility). At our company it was acquired laziness, because we have an automated build tool that compiles all of our projects for us, and one of the main features of the tool is that is can automatically repair broken project references between projects. Since the build tool fixes this for us, there is less incentive to use Binary Compatibility.
Why Binary Compatibility is better (or...why you shouldn't do what we do)
A few reasons why Binary Compatibility is usually the better choice:
Microsoft says so
If all your components are binary compatible with previous releases of your software, you can easily recompile a single component and redistribute it to your customers. This makes bugfixes/patches easier to deploy. If you use No Compatibility on your projects, you will have to recompile and redistribute your entire application every time a small patch needs to go out, because the newer components (probably) won't work with the older components.
You are doing your part to uphold the COM standard: In COM, class ID's and interface ID's are supposed to uniquely identify a class or interface. If your classes and/or interfaces haven't changed between builds, then there is no reason to generate new ID's for those classes and interfaces (in fact, then the same class would have multiple ID's). Binary Compatiblity allows you to maintain the same ID's across builds, which means you are being a good citizen and following COM conventions.
Less Registry noise. If you are always deploying new components to customers that aren't binary compatible with old versions, each new version will add new information to the registry. Each new interface and class ID has to registered, among other things. If you keep everything Binary Compatible, then an installer only has to add the registry keys in one place, since your class ID's and interface ID's won't change.
If you are exposing a public API or component that other third party applications are consuming, you will definitely want to use Binary Compatibility so that you don't break third party software that depends on your code.
Visual Build Pro。 如果您仍然停留在 VB6 领域,并且必须构建专业产品,我强烈建议您研究这个产品。 它可以免费试用,而且物有所值(而且它在 .Net 和其他平台的持续集成方面做得非常好。)自从我们开始使用它以来,它在每个版本中都将我们从 DLL 地狱中拯救出来。 据我所知,没有其他方法可以在 VB6 中创建一个像样的构建框。
Visual Build Pro. If you are still stuck in VB6 land, and have to build professional products I highly recommend you look into this product. It has a free trial and is worth every penny (plus it does a pretty good job of continuous integration for .Net and other platforms.) It has saved us from DLL hell on every release since we started using it. There is no other way I know of to create a decent build box in VB6.
正如 Mike Spross 建议的那样,您应该使用二进制兼容性。 您可以(并且应该)在干净的机器上进行构建。 您可以通过将当前生产二进制文件(ActiveX DLL 和 OCX)的副本保留在源代码管理系统的“兼容”目录中来实现此目的。 当您选择二进制兼容性时,所有项目都应引用此副本。 例如,将新的二进制文件放入 ...\Release 中,而兼容的二进制文件位于 ...\Compatible 中。 当新版本投入生产时,您将所有内容从 ...\Release 复制到 ...\Compatible。 通过这种方式,您可以保持从一个版本到下一版本的兼容性。
在二进制兼容模式下,如果您向类中添加新方法,VB 将创建一个新的 IID。 请记住,在 COM 中,接口是不可变的。 如果你对界面做出最微小的改变,你就创造了一些新的东西。 VB 遵守 COM 的这一规则,但使用了一些烟雾和烟雾。 镜像以防止破坏旧的客户端代码。 因为VB“知道”新接口是旧接口的100%超集(这是二进制兼容性所保证的),所以它可以使用“接口转发”。 接口转发只是将所有引用从旧接口重定向到新接口。 如果没有这个技巧,您将不得不为您修改的任何 ActiveX 组件创建新版本(具有不同的名称和 CLSID)。 DLL Hell 会变成 DLL Armargeddon!
VB 将所有接口转发信息存储在组件的资源中。 当您注册组件时,它会将所有接口 IID 写入 HKCR\Interface。 较旧的接口将包含转发信息。 只有“真正的”接口才会引用实际的组件类。
As Mike Spross suggests, you should use Binary Compatibility. You can (and should) build on a clean machine. You do this by keeping a copy of the current production binaries (ActiveX DLLs & OCXs) in a "compatible" directory in your source control system. All the projects should refer to this copy when you select Binary Comatibility. For example, put the new binaries into ...\Release and the compatible binaries live in ...\Compatible. When the new version goes into production you copy everything from ...\Release to ...\Compatible. In this way you keep the compatibility going from one release to the next.
When in Binary Compatibility mode, VB will create a new IID if you add a new method to your class. Remember that in COM an interface is immutable. If you make the slightest change to an interface, you are creating something new. VB observes this rule of COM, but uses some smoke & mirrors to prevent breaking older client code. Because VB "knows" that the new interface is a 100% superset of the old interface (this is what Binary Compatibility ensures), it can use "interface forwarding". Interface forwarding merely redirects all references from the old interface to the new interface. Without this trick, you would have to create new versions (with different names & CLSIDs) of any ActiveX component you modify. DLL Hell would turn into DLL Armargeddon!
VB stores all the interface forwarding info in the resources of your component. When you register the component it writes all the interface IIDs to HKCR\Interface. The older interfaces will have forwarding info in them. Only the "real" interface will refer to an actual coclass.