C++ 的推荐迁移策略Visual Studio 6 中的项目
对于使用 Visual Studio 6 用 C++ 编写的大型应用程序,进入现代时代的最佳方式是什么?
我想采用增量方法,例如,我们慢慢移动部分代码并将新功能写入 C# 中,然后将其编译到可以从旧应用程序中引用的库或 dll 中。
这可能吗?最好的方法是什么?
编辑:目前我们仅限于 Express 版本,我认为该版本不允许使用我们当前应用程序中大量使用的 MFC 库。它也是一个相当大的应用程序,具有很多硬件依赖性,因此我认为不会进行大规模迁移。
Edit2:我们研究过用 C# 编写 COM 包装的组件,但没有 COM 经验,这既可怕又复杂。是否有可能生成一个具有直接 C 接口的 C# dll,并将所有托管优点隐藏在其中?或者 COM 是一种不可避免的罪恶吗?
For a large application written in C++ using Visual Studio 6, what is the best way to move into the modern era?
I'd like to take an incremental approach where we slowly move portions of the code and write new features into C# for example and compile that into a library or dll that can be referenced from the legacy application.
Is this possible and what is the best way to do it?
Edit: At this point we are limited to the Express editions which I believe don't allow use of the MFC libraries which are heavily used in our current app. It's also quite a large app with a lot of hardware dependencies so I don't think a wholesale migration is in the cards.
Edit2: We've looked into writing COM-wrapped components in C# but having no COM experience this is scary and complicated. Is it possible to generate a C# dll with a straight-C interface with all the managed goodness hidden inside? Or is COM a necessary evil?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
这是唯一现实的方法
首先,你使用什么样的版本控制? (如果您使用分支版本控制,它允许您进行实验并查看什么有效,同时最大限度地降低代码受损的风险;其他版本控制也可以,但您必须非常小心,具体取决于您使用的内容)。
编辑:我刚刚看到您正在使用 SVN。如果您有自由的话,迁移到 Mercurial 或 git 可能是值得的(这一变化使您可以使用代码库实现巨大的飞跃)。
这……不一定是个好主意。 C# 代码可以公开可在 C++ 中访问的 COM 接口。用 C++ 为用 C# 编写的模块编写客户端代码可能很有趣,但您可能会发现它很费力(就工作量与收益比而言);它也很慢并且容易出错(与为用 C++ 编写的模块编写 C# 客户端代码相比)。
最好考虑用 C# 创建应用程序框架,并使用(已经)用 C++ 编写的模块来实现核心功能。
是的,这是可能的。
有多少人参与该项目?
如果有很多,最好的方法是让一些(两个?四个?)在新的应用程序框架上工作,其余的继续照常进行。
如果人少,可以考虑安排一个人负责,或者更多人兼职。
每个(旧代码维护和新代码开发)分配的人员/精力百分比应取决于团队的规模和您的优先级(过渡是低优先级问题吗?是否有必要在给定日期之前完成?)
做到这一点的最佳方法是开始调整代码模块,使其可在多种场景中使用(旧代码和新代码),并继续并行开发(同样,通过使用分支分布式可以大大缓解这一问题)版本控制系统)。
以下是我的做法(迭代开发,中间有小步骤和大量有效性检查):
在旧代码库中选择一个功能模块(与 GUI 无关的东西)。
从步骤 1 中选择的模块中删除 MFC 代码(以及 VS2010 Express 中不可用的其他库 - 例如 ATL)引用。
不要尝试用自定义代码重写 MFC/ATL 功能,除非进行小的更改(即决定创建自己的 GUI 框架是不可行的,但决定编写自己的 COM 接口指针是可以的)类似于 ATL 的 CComPtr 的包装器)。
如果代码严重依赖于某个库,最好尽可能将其分开,然后将其标记下来以便将来使用新技术重写。无论哪种方式,对于严重依赖于 MFC 的库,您最好使用其他内容(C#?)重写代码。
尽可能减少与所选模块的耦合(确保代码位于单独的库中,明确决定模块向客户端代码公开哪些功能),并仅通过决定的公开接口访问分隔的功能(在旧版本中)代码)。
确保旧的代码库仍然适用于修改后的模块(测试 - 最终自动化此模块的测试) - 如果您仍需要保留,这一点至关重要直到您可以发布新版本为止。
在维护当前应用程序的同时,启动一个新项目(基于 C#?),该项目实现 GUI 和您需要现代化的其他部分(例如严重依赖 MFC 的部分)。这应该是一个薄层应用程序,最好与业务逻辑无关(业务逻辑应尽可能保留在遗留代码中)。
根据旧代码的用途和您定义的接口,对于部分代码使用 C++/CLI 而不是 C# 可能是有意义的(它可以与本机 C++ 指针和托管代码一起使用,允许您创建一个在托管 .NET 代码和 C++ 本机代码之间进行通信时可以轻松转换)。
让新应用程序使用在步骤 1 中选择的模块。
选择一个新模块,返回到步骤 2。
优点:
将进行重构(模块分离所必需)
最后你应该对您的功能模块进行一系列测试(如果您还没有)。
您仍然有一些东西需要运送。
一些注意事项:
如果您不使用分布式分支版本控制系统,那么最好一次只处理一个模块。如果您使用分支/分布式源代码控制,您可以将不同的模块分发给不同的团队成员,并在每次移植新内容时集中更改。
明确界定每个步骤非常重要(以便您可以将更改回滚到最后一个稳定版本,尝试新事物等等)。这是另一个使用 SVN 很难而使用 Mercurial / Git 很容易的问题。
开始之前,将所有项目文件的名称更改为具有 .2005.vcproj 扩展名,并对解决方案文件执行相同的操作。创建新项目文件时,对项目文件和解决方案的 .2010.vcxproj 执行相同操作(如果转换解决方案/项目,您仍应执行此操作)。这个想法是,您应该并行使用并在任何时候打开您想要的任何一个。您不必为了切换 IDE 而对源代码管理中的不同标签/标签/日期进行源代码树更新。
您仍然可以通过编写包装器代码来做到这一点(例如,COM 接口的小型模板化智能指针类不会出错 - 类似于 ATL 中的 CComPtr)。如果您将 COM 代码隔离在一些包装器后面,您可以编写客户端代码(与 COM 无关)(几乎)没有问题。
据我所知没有。我认为如果您计划使用用 C# 编写的服务器代码和用 C++ 编写的客户端代码,COM 将是一个不可避免的邪恶。
反过来也有可能。
That's the only realistic way to do it.
First, what kind of version control do you use? (If you use branching version control that allows you to make experiments and see what works, while minimizing the risk of compromising your code; others are OK also, but you'll have to be really careful depending on what you are using).
Edit: I just saw you are using SVN. It may be worthwile to move to mercurial or git if you have the liberty to do that (the change provides a quantum leap in what you can do with the code-base).
That's ... not necessarily a good idea. C# code can expose COM interfaces that are accessible in C++. Writing client code in C++ for modules written in C# can be fun, but you may find it taxing (in terms of effort to benefits ratio); It is also slow and error-prone (compared to writing C# client code for modules written in C++).
Better consider creating an application framework in C# and using modules (already) written in C++ for the core functionality.
Yes, it's possible.
How many people are involved in the project?
If there are many, the best way would be to have a few (two? four?) work on the new application framework and have the rest continue as usual.
If there are few, you can consider having either a person in charge of this, or more people working part-time on it.
The percentage of people/effort assigned on each (old code maintenance and new code development) should depend on the size of the team and your priorities (Is the transition a low priority issue? Is it necessary to be finished by a given date?)
The best way to do this would be to start adapting modules of the code to be usable in multiple scenarios (with both the old code and the new one) and continue development in parallel (again, this would be greatly eased by using a branching distributed version control system).
Here's how I would go about it (iterative development, with small steps and lots of validity checks in between):
Pick a functional module (something that is not GUI-related) in the old code-base.
Remove MFC code (and other libraries not available in VS2010 Express - like ATL) references from the module picked in step 1.
Do not attempt to rewrite MFC/ATL functionality with custom code, unless for small changes (that is, it is not feasible to decide to create your own GUI framework, but it is OK to decide to write your own COM interface pointer wrapper similar to ATL's CComPtr).
If the code is heavily dependent on a library, better separate it as much as possible, then mark it down to be rewritten at a future point using new technologies. Either way, for a library heavily-dependent on MFC you're better off rewriting the code using something else (C#?).
reduce coupling with the chosen module as much as possible (make sure the code is in a separate library, decide clearly what functionality the module exposes to client code) and access the delimited functionality only through the decided exposed interface (in the old code).
Make sure the old code base still works with the modified module (test - eventually automate the testing for this module) - this is critical if you need to still stay in the market until you can ship the new version.
While maintaining the current application, start a new project (C# based?) that implements the GUI and other parts you need to modernize (like the parts heavily-dependent on MFC). This should be a thin-layer application, preferably agnostic of the business logic (which should remain in the legacy code as much as possible).
Depending on what the old code does and the interfaces you define, it may make sense to use C++/CLI instead of C# for parts of the code (it can work with native C++ pointers and managed code, allowing you to make an easy transition when comunicating between managed .NET code and C++ native code).
Make the new application use the module picked in step 1.
Pick a new module, go back to step 2.
Advantages:
refactoring will be performed (necessary for the separation of modules)
at the end you should have a battery of tests for your functional modules (if you do not already).
you still have something to ship in between.
A few notes:
If you do not use a distributed branching version control system, you're better off working on one module at a time. If you use branching/distributed source control, you can distribute different modules to different team members, and centralize the changes every time something new has been ported.
It is very important that each step is clearly delimited (so that you can roll back your changes to the last stable version, try new things and so on). This is another issue that is difficult with SVN and easy with Mercurial / Git.
Before starting, change the names of all your project files to have a .2005.vcproj extension, and do the same for the solution file. When creating the new project file, do the same with .2010.vcxproj for the project files and solution (you should still do this if you convert the solutions/projects). The idea is that you should have both in parallel and open whichever you want at any point. You shouldn't have to make a source-tree update to a different label/tag/date in source control just to switch IDEs.
You can still do it, by writing wrapper code (a small templated smart pointer class for COM interfaces wouldn't go amiss for example - similar to CComPtr in ATL). If you isolated the COM code behind some wrappers you could write client code (agnostic of COM) with (almost) no problems.
Not that I know of. I think COM will be a necessary evil if you plan to use server code written in C# and client code in C++.
It is possible the other way around.
面对同样的任务,我的策略可能是这样的:
确定我们希望通过转向 2010 年开发获得什么 - 可能是
确定系统的哪些部分不会从迁移到 C# 中获益:
Identify系统的哪些部分需要迁移到c#。对于这些部分,请确保 C++ 中的当前实现是解耦和模块化的,以便可以替换这些部分。如果应用程序是一个整体,那么需要大量的工作来重构应用程序,以便可以将其分解并选择在 C# 中重新实现的部分。 (可以不重构任何内容,而只专注于在 C# 中实现新的应用程序功能。)
现在您已经确定了哪些部分将保留在 C++ 中以及哪些部分将在 C# 中实现,(或者只是规定新的应用程序功能)功能在 C# 中),然后焦点转向如何将 C# 和 C++ 集成到单个解决方案中
混合 MFC UI 和 c# UI 可能无法实现,也不建议这样做,因为它会产生两种不同风格的 UI 混合(1990 年代的灰色和 2010 年代的氛围)。专注于实现增量迁移会更简单,例如在 C# 中实现新的应用程序代码并从本机 C++ 代码中调用它。这使得迁移的 C# 代码量一开始就很小。随着您对 2010 年开发的了解越来越多,您就可以获取无法增量迁移的较大块,例如 UI。
Faced with the same task, my strategy would be something like:
Identify what we hope to gain by moving to 2010 development - it could be
Identify which parts of the system will not gain from being moved to C#:
Identify which parts of the system need to be migrated to c#. For these parts, ensure that the current implementation in C++ is decoupled and modular so that those parts can be swapped out. If the app is a monolith, then considerable work will be needed refactoring the app so that it can be broken up and select pieces reimplemented in c#. (It is possible to refactor nothing, instead just focus on implementing new application functionality in c#.)
Now that you've identified which parts will remain in C++ and which parts will be implemented in c#, (or just stipulate that new features are in c#) then focus turns to how to integrate c# and c++ into a single solution
Mixing the MFC UI and c# UI is probably not achieveable, and not adviseable either as it would produce a UI mix of two distinct styles (1990s grey and 2010 vibe). It is simpler to focus on achieving incremental migration, such as implementing new application code in c# and calling that from the native C++ code. This keeps the amount of migrated c# code small to begin with. As you get more into the 2010 development, you can then take the larger chunks that cannot be migrated incrementally, such as the UI.
首先,你对现代的定义是有争议的。没有理由认为 C# 在任何意义上都比 C++ 更好。关于 C# 是否可以帮助您更好地避免内存管理错误已经说了很多,但对于 C++ 中的现代设施来说,情况并非如此,而且,在资源获取时序方面很容易与 C# 搞混,这可能取决于什么其他程序正在做。
First, your definition of modern era is controversial. There's no reason to assume C# is better in any sense than C++. A lot has been said on whether C# helps you better avoid memory management errors, but this is hardly so with modern facilities in C++, and, it's very easy to do mess with C# in terms of resource acquisition timing, that may be dependent on what other programs are doing.
如果直接从 6 移动到 2010,您可能会遇到一些混乱的项目设置。如果这不是一个相当大的项目,并且是您需要转换的少数项目之一,那么应该没问题。只要在2010年打开它,然后按照转换向导操作即可。请务必先备份您的项目,并在完成后验证您的项目设置。
在我看来,最好的方法是通过 Visual Studio 的每次迭代逐步转换它。从 2003 年到 2010 年,我必须对 1400 个项目进行现代化改造,我发现最好的方法是将所有内容都转换为 2005 年,然后转换为 2008 年,最后转换为 2010 年。这对我来说出现的问题最少。
如果您只有 6 个最新的 Visual Studio,您可能最终只能尝试使用向导直接转到新的 Visual Studio。在一切再次正确构建之前,需要进行一些手动清理。
另外,再一次,请先备份! :)
If you move straight from 6 to 2010 you may end up with some messed up project settings. If this isn't a fairly large project, and it's one of few that you need to convert, then that should be fine. Just open it in 2010, and follow the conversion wizard. Make sure to back up your project first, and verify your project settings when you're done.
In my opinion though the best way is to convert it step by step through each iteration of Visual Studio. I had to modernize 1400 projects from 2003 to 2010, and the best way that I found was to convert everything to 2005, then to 2008, and then finally to 2010. This caused the least amount of issues to arise for me.
If you only have 6 and the newest Visual Studio you may end up just having to try and go straight to the new one using the wizard. Expect some manual cleanup before everything builds correctly for you again.
Also, one more time, BACK IT UP FIRST! :)
高级 C++ 代码调用低级 C# 代码看起来不是一个好主意。 .NET 语言更好的领域是用户界面、数据库访问、网络、XML 文件处理。计算、硬件访问等低级内容最好保留为本机 C++ 代码。
转向 .NET,在大多数情况下,最好使用 WPF 或 Windows 窗体技术完全重写 UI。低级内容仍然是本机的,并且使用不同的互操作性技术来连接 C# 和本机代码:PInvoke、C++/CLI 包装器或 COM 互操作性。一段时间后,您可能会决定用 C# 重写低级本机组件,除非确实有必要。
关于在 VS2010 中编译本机 C++ 代码 - 我没有看到任何问题。只需修复所有编译错误 - 新编译器具有更严格的类型检查和语法限制,并在编译时捕获更多错误。
High-level C++ code calling low-level C# code doesn't look like a good idea. The areas where .NET languages are better, are user interface, database access, networking, XML files handling. Low-level stuff like calculations, hardware access etc. is better to keep as native C++ code.
Moving to .NET, in most cases it is better to rewrite UI completely, using WPF or Windows Forms technologies. Low-level stuff remains native, and different interoperability technologies are used to connect C# and native code: PInvoke, C++/CLI wrappers or COM interoperability. After some time, you may decide to rewrite low-level native components in C#, only if it is really necessary.
About compiling native C++ code in VS2010 - I don't see any problems. Just fix all compilation errors - new compilers have more strict type checking and syntax restrictions, and catch much more bugs at compilation time.
不知道为什么这么多人提倡 COM。如果您还没有使用大量 COM,那么学习如何在 C++ 端执行此操作将会很麻烦,而且您将使用托管端可能最慢的互操作。不是我的第一选择。
理想情况下,您已经根据业务逻辑重构了 UI。然后,您可以构建新的 UI(WPF、WinForms、ASP.NET、支持其他客户端的 Web 服务等)并通过 P/Invoke 或编写 C++/CLI 包装器调用您的业务逻辑。 @mdma 为您提供了很好的建议,假设重构是可能的。
但是如果你付钱让我进来帮助你,我的第一个问题就是你为什么要这样做?一些客户表示他们不想再向 C++ 开发人员付费,因此他们希望所有 C++ 代码都消失。这是一个可怕的目标,因为我们都讨厌接触有效的代码。一些客户希望将他们的逻辑暴露给 ASP.NET 或 Reporting Services 等,因此对于他们,我们专注于重构。有人说“看起来就像 1999 年的样子”,我向他们展示了 MFC 现在的样子。颜色、皮肤/主题(包括 Office 和 win7 外观)、功能区、浮动/停靠窗格和窗口、Windows 7 任务栏集成...如果您只是想看起来不同,看看 VS 2010 中的 MFC,您可能不需要调整任何代码都可以。
最后为了使 VS 2010 的非 Express 版本变得经济实惠,请查看 Microsoft 合作伙伴计划。如果您已将软件出售给至少 3 位仍然与您交谈的客户,并且可以通过 Windows 7 徽标自检(我在一两天内就通过了 VB 6 应用程序),那么您可以拥有 5-10 个副本所有产品(Windows、Office、VS)的费用为每年 1900 美元左右,具体取决于您居住的地方。
Not sure why so many folks are advocating for COM. If you haven't already got a lot of COM in there, learning how to do it on the C++ side is going to hurt, and then you're using the slowest possible interop from the managed side. Not my first choice.
Ideally you have refactored your UI from your business logic. You can then build a new UI (WPF, WinForms, ASP.NET, web services that support some other client, whatever) and call into your business logic through P/Invoke or by writing a C++/CLI wrapper. @mdma has good advice for you assuming that the refactoring is possible.
However if you were paying me to come in and help you my very first question would be why do you want to do this? Some clients say they don't want to pay C++ devs any more, so they want all the C++ code gone. This is a scary objective because we all hate to touch code that works. Some clients want to expose their logic to ASP.NET or Reporting Services or something, so for them we concentrate on the refactoring. And some say "it looks so 1999" and for them I show them what MFC looks like now. Colours, skinning/theming including office and win7 looks, ribbon, floating/docking panes and windows, Windows 7 taskbar integration ... if you just want to look different, take a look at MFC in VS 2010 and you might not have to adjust any code at all.
Finally to make non-Express versions of VS 2010 affordable look into the Microsoft Partner Program. If you have sold your software to at least 3 customers who still speak to you, and can get through the Windows 7 logo self test (I have got VB 6 apps through that in a day or two) then you can have 5-10 copies of everything (Windows, Office, VS) for $1900 or so a year, depending on where you live.
首先,我会尝试保留尽可能多的代码以避免重写。在开始转换之前,我还会删除所有未使用的代码。
自 VC++ 6.0 以来,Microsoft 更改了 MFC 库和 C++ 标准库。
我建议开始构建没有依赖项的 DLL,然后查看第三方库,然后一次重建一个依赖项 DLL/EXE。
引入单元测试以确保代码的行为不会改变。
如果您使用不同版本的 VC++ 进行混合构建,则需要防止在使用不同版本的 VC 运行时的 DLL 之间传递资源(文件句柄)。
To start I'd try and keep as much code as possible to avoid a rewrite. I'd also remove all unused code before starting the conversion.
Since VC++ 6.0 Microsoft changed the MFC libraries and the C++ Standard Library.
I recommend to start building your DLLs with no dependencies, then looking at your third party libraries, and then rebuild one dependent DLL/EXE at a time.
Introduce unit tests to make sure the behaviour of code does not change.
If you have a mixed build, using different versions of VC++, you need to guard against passing resources (file handles) between DLLs that use different versions of the VC runtime.
如果经济上可能的话,我会强烈考虑只为您需要的 Visual Studio 版本付费,因为您很可能会在花费的时间上损失更多的钱。我对 Express 版本了解不够,无法给出很好的答案,但在集成来自分包商的一些用 C++ 编写的代码时,我使用了 C++ / CLI。您可能能够重用大部分代码库并熟悉该语言,但您还可以访问托管代码和库。另外,如果您想开始用 C# 编写新代码,您也可以这样做。我遇到的最大问题是,在 VS 2010 中,C++/CLI 中没有智能感知。
If at all financially possible I would strongly consider just paying the money for the version of Visual Studio that you need because you could very well lose more money on the time you spend. I do not know enough about the express editions to give a good answer on them but when integrating some code from a subcontractor that was written in C++ I used C++ / CLI. You will probably be able to reuse most of your codebase and will be familiar with the language but you will also have access to managed code and libraries. Also if you want to start writing new code in C# you can do that. The biggest problem I had with it was that in VS 2010 there is no intellisense in C++ / CLI.
Visual Studio 6 因漏洞多且速度慢而闻名。进入现代时代最好的方法是获得一个新的编译器。最简单的方法可能是将遗留应用程序写入 DLL,然后将 exe 写入 C# 并使用 P/Invoke。然后你就再也不用接触旧代码了——你可以用 C# 编写越来越多的代码,而使用越来越少的旧 DLL。
如果您的旧代码非常注重 OO,您可以使用 C++/CLI 编写包装类,允许 .NET 调用 C++ 对象上的方法,如果您使用引用计数智能指针,也可以收集它们。
Visual Studio 6 is legendary for being buggy and slow. Moving into the modern era would best be done by getting a new compiler. What is probably the easiest thing to do is write the legacy app into a DLL, then write your exe into C# and use P/Invoke. Then you never have to touch the old code again- you can just write more and more in C# and use less and less of the old DLL.
If your old code is very heavily OO, you can use C++/CLI to write wrapper classes that allow .NET to call methods on C++ objects, and collect them too if you use a reference counted smart pointer.
您可以使用 C# 通过 COM 或 COM+ (System.EnterpriseServices) 包装器编写新组件,该包装器可从现有 C++ 代码中调用。
You can use C# to write your new components with a COM or COM+ (System.EnterpriseServices) wrapper, which will be callable from your existing C++ code.