This page describes the process and issues you face when upgrading your legacy OWL applications written in Borland C++ to OWLNext and a modern compiler.
Maybe your legacy OWL applications are working fine, and you are happy maintaining them using good old Borland C++ 5.02. Why should you upgrade to OWLNext? Here is a list of benefits from upgrading:
If you, like many OWL users around the world, have found the need to inspect, understand and work with the OWL source code itself, you will appreciate that OWLNext has also made a lot of clean-up and improvements to the source code, such as the removal of the obsolete Win16 stuff and the addition of in-source documentation (Doxygen), all of which makes OWL application maintenance easier.
Most of the C++ world has moved on since Borland C++, but you can still use the good old Borland C++ IDE as a stepping stone to get your applications working with OWLNext in a familiar environment before moving on to modern tools. However, OWLNext 6.30 is the last version with support for the Borland C++ 5.02 compiler. By installing the free Borland C++ 5.5 compiler update, you can upgrade further to OWLNext 6.36. But that is the end of the line. Since version 6.40, OWLNext no longer supports Borland C++.
We recommend that you upgrade to current modern development tools. We have worked hard to make sure that OWLNext works with the latest compilers. See Supported Compilers for more advice on selecting a modern replacement for Borland C++.
OWLNext is based on 32-bit OWL 5. If you have 16-bit (Win16) code, or code based on earlier versions of OWL, then you need to upgrade your code to 32-bit (Win32) and OWL 5 before migrating to OWLNext (see Further reading and Links). You may also need to make additional adaptations of your code due to various changes made in OWLNext. Some of these changes can be reverted by using the OWL5_COMPAT build option. But in general you may need to update your code.
Also note that the latest version of OWLNext (currently the 7-series) only supports Windows Vista and later versions. The OWLNext 6.40 series supports Windows XP as well. If you need support for even earlier Windows versions, you may have to go back to OWLNext 6.30 or even 6.20. However, to fully benefit from our many enhancements and bug fixes, we recommend you target Vista or later with the latest version of OWLNext.
To port an OWL 5 legacy application to OWLNext, we recommend a series of stepping stones to make the porting process as painless as possible:
Note that OWLNext 6.36 is a strategic version in the upgrade process. It is officially supported as a migration stepping stone, and hence has the widest compiler support, including support for the latest compiler versions. So with 6.36, you can switch to modern development tools.
However, if your code base is small, and you have a good understanding of the changes in OWLNext, you may be able to skip some of the intermediate steps above. The best path may also depend on the destination. For example, if you plan to use Microsoft Visual Studio development tools, then after making sure your project builds successfully with Borland C++ 5.02 and OWLNext 6.30, you can immediately switch to Visual Studio 2012 (this is the latest version supported by OWLNext 6.30). Afterwards, you can upgrade to later versions of OWLNext and Visual Studio as you see fit. For more information on porting your OWL application to the Microsoft compiler, see Migrating from Borland C++ 5.02 to Visual C++.
See our Installation Guide for instructions on how to install any version of OWLNext. See the sections below for information about the changes you may have to make to your code.
OWLNext is still largely compatible with OWL 5, but some changes have been made to correct, improve or simplify the API, and some obsolete features have been dropped. The following sections describe these changes. See OWLNext Releases for the full release history and revision log.
The core of OWLNext now lives in the "owl" namespace. OWLNext 6.32 renamed the namespace from "OWL" to "owl". A macro for the old namespace is available in OWL5_COMPAT mode. Unlike the original OWL, the use of namespaces is now mandatory, and the old macros related to namespaces have been removed (BI_NAMESPACE etc.). If your legacy code does not already use namespaces, you must qualify (by "owl::") all OWL types etc. in your headers and add a using directive ("using namespace owl;") to your implementation files. Similar changes apply to the extension libraries (OCFNext, OWLExt, CoolPrj).
See the FAQ for some tips on how to efficiently apply namespace qualification in your headers using search-and-replace.
Originally, OWL used the old exception class xmsg as the base class for TXBase, which in turn is the base class for TXOwl and the derived exception classes, TXWindow etc. OWLNext now uses std::exception as the base class for TXBase. For more information about exception handling, see Exceptions and OWLNext.
OWLNext has transitioned to the standard C++ library, and hence no longer uses the Borland C++ Class Libraries. The required functionality from these libraries, such as the persistent streams framework, has been moved directly into OWLNext.
For legacy application support and compatibility with non-Borland compilers, OWLNext contains code that simulates parts of the Borland libraries. But please note that this code is incomplete, unreliable and no longer maintained. In particular, beware that detailed requirements for class copy construction and assignment etc. may not be 100% compatible, and this may introduce bugs in your code that are hard to pinpoint.
Ideally, you should rewrite your code to use the standard C++ library or other alternatives instead. For example, the Borland 'string' class has been replaced by owl::tstring, which is an alias for std::string or std::wstring, depending on the UNICODE build mode. The Borland exception classes (xmsg etc.) have been replaced by the equivalent standard C++ classes. And, instead of the Borland container classes (e.g. TArrayAsVector), use the containers in the standard C++ library (e.g. std::vector). For more information on rewriting your code, see Replacing the Borland C++ Class Libraries.
Note that the simulated components of the Borland C++ Class Libraries are all deprecated and may be dropped in a future release.
Over the years we have made numerous improvements to the Windows message dispatch framework at the core of OWLNext. Most of these changes concern low-level implementation, such as an overhaul of the implementation of window procedures (thunks) to support DEP and 64-bit compilation. These changes do not affect the API.
However, we have made many corrections to the event handler signatures, and this may require changes in your program. In particular, OWLNext 6.40 introduced a major overhaul of the message dispatch machinery, and many event handler signatures were updated in the process. In addition, OWLNext 6.40 now requires that the event handler for a response table entry is declared in the class owning the table. Using a base class function is no longer allowed (see FAQ).
The changes in OWLNext 6.40 also affect how response tables and dispatch functions are implemented, so if you have custom response table entries, such as custom DocView notifications (see FAQ), or any other code that depends on the implementation of the response table macros, table layout or dispatch functions, you will have to update your code.
For more information about the dispatch machinery and the changes, see Windows Message Dispatch in OWLNext.
The OWL transfer buffer mechanism, designed to transfer data to and from dialog boxes, inherently requires byte packing. Byte packing was the default in Borland C++, so this was then not an issue. Modern compilers, on the other hand, align structure members on the natural (most efficient) boundaries for the primitive CPU data types, thus potentially introducing gaps between members. You must hence ensure byte packing explicitly by adding compiler pragma directives around your transfer buffer structures (see FAQ).
OWLNext 6.32 replaces the TWindow::SetTransferBuffer (void*) function by overloads that infer or accept the size of the buffer. The size is used to check for packing compliance, buffer overruns and field type mismatches. If you have defined the transfer buffer as a struct, class or array then the new function template overloads will automatically deduce the size of the buffer, provided you pass an argument of the corresponding type. Alternatively, you can pass the size explicitly as the second argument. The old function signature is available in OWL5_COMPAT mode, but note that it will disable the buffer checks.
Transfer buffers suffer from poor design and implementation making them unsafe. For this reason the Safe Transfer Buffers feature was introduced in OWLNext 6.32. By using this feature you can make your legacy transfer buffers fully safe with very little effort. Alternatively, you may want to rewrite your code to use the new Dialog Data Transfer framework.
Many obsolete OWL features that no longer make sense today have been removed. For example, OWLNext now only supports modern themed Windows, and the BWCC and CTL3D control libraries are hence outdated. However, up until OWLNext 6.34, BWCC support can be reinstated by using the OWL5_COMPAT mode.
In 6.32 we also removed the custom implementation of the Windows controls. OWL 5 offered this feature to provide emulation of the Windows 95 controls in Windows 3.x. Since we no longer support Win16, this feature was removed, thereby simplifying the maintenance of the source code. The control classes encapsulating the Windows controls now always use the native Windows implementation. The related class TNativeUse was removed, as well as the related functions, such as TControl::GetNativeUse and TSlider::SetNativeUse. As a special case, to maintain support for legacy code, TGauge was changed to a pure OWL control and deprecated (it has since moved to OWLExt [r5913]). A new class, TProgressBar, was introduced to encapsulate the Windows common control (Progress Bar). For details, see [r1084].
Other features that have been removed include the support for Win16 (16-bit compilation), Unicows (Microsoft Layer for Unicode) and static library sectioning (piecemeal compilation of source files).
OWLNext 6.44 and earlier versions have two very different overloads of TWindow::GetClassName. The public one, TWindow::GetClassName (LPTSTR className, int maxCount), is just a wrapper around the Windows API function of the same name, GetClassName, and it can be used to get the class name as a string.
However, the protected one, GetClassName (), is not a wrapper around the Windows API. In OWLNext 6.44 and earlier, the protected GetClassName overload is a virtual function that allows derived classes to override it and specify the class name to be used to register the window class. It is called by TWindow::Register and TWindow::GetWindowClass, and in the latter it is used to set WNDCLASS::lpszClassName. Note that according to the Windows API the value of this field can be a C-string or an ATOM. This means that the protected GetClassName () may not return a valid string. If it returns an ATOM, and you treat it as a string, you will get a crash. The protected overload should hence not be used to get the window class name in general. Use the public overload for that.
In OWLNext 7, we have resolved this ugly overload and return-type problem by renaming the protected function to GetWindowClassName and changing the return type to TWindowClassName. This new and safe return type encapsulates the class name union type (in much the same way as TResId encapsulates the union between a C-string and an integer resource identifier).
See "GetClassName is not type-safe" [bugs:#348] for more information about this resolution.
This change in the API means that you will need to update your code if you have custom controls, dialogs or windows that override the old protected GetClassName to return a custom window class name. For OWLNext 7 compatibility, you must rename your override to GetWindowClassName and change the return type to TWindowClassName. In general, we also recommend you use the override keyword (since C++11), to ensure that you get override signatures correct.
Note that the public TWindow::GetClassName (LPTSTR className, int maxCount) is still present in OWLNext 7, and as before, it is just a low-level wrapper around the Windows API function.
OWLNext makes a lot of minor API changes to correct issues and improve the interface, e.g. ensure compliance with the Windows API, support 64-bit build mode (see 64-bit OWLNext), enforce const-correctness (see FAQ), introduce standard string class support (see Strings in OWLNext), replace pointer parameters by references, protect against unintended implicit conversions (for example, int and long are no longer implicitly converted to TColor, see FAQ), remove use of undocumented Win32 functions [bugs:#342], and redesign unsafe classes such as TPointer [bugs:#159]. Most often these changes will produce compilation errors in old code that are easily recognised and simple to fix.
However, some changes may silently correct wrong behaviour, such as the bug fix for the calling sequence issue regarding TWindow::SetupWindow and TWindow::TransferData [bugs:#102]. In rare circumstances, a program may depend on the old incorrect behaviour, and thus require a little more attention to adapt it to the new corrected behaviour.
For changes in OWLNext 7, see "Help on incompatible changes in 7 series" [discussion:e7350279af].
See OWL Compatibility Modes for a list of revertible API changes and our release documentation and bug tracker for details on the bigger issues.
Also see FAQ | Porting issues.
If you run into problems with upgrading your code to OWLNext, make sure you have a look at our FAQ. Also, make sure you thoroughly read the information presented in the sections above, including the linked material provided. For a deeper understanding of the library, see Further reading below.
If you remain stuck, try reaching out on our Open Discussion forum. For reporting problems, see "FAQ | How do I report an issue?".
Bugs: #102
Bugs: #159
Bugs: #342
Bugs: #348
Bugs: #373
Commit: [r1084]
Commit: [r5913]
Discussion: 97175
Discussion: EV_WM_LBUTTONDOWN, EV_WM_SIZE and some others cause errors in VS 2013
Discussion: Controls loosing window handle after upgrading owlnext
Discussion: Update 6.30 with OWLNext patch 6.30.12 and use OWLMaker Build 3175
Discussion: Upgrade advice
Discussion: Upgrade to OWLNext with ease (documentation, tips, FAQ, etc.)
Discussion: Persistence support
Discussion: Array replacement
Discussion: Array replacement
Discussion: [6.44] Question(s) about Event crackers
Discussion: Experimenting OWL6.30 to OWL6.42
Discussion: Unsupported Compiler Version fatal error C1189 when switching to OWLNEXT 7
Discussion: Converting from OWL 1.0 - how clean do I have to be?
Discussion: Can I upgrade OWLNext 6.30 to Visual Studio 2019?
Discussion: OWLNext Framework with old OWL code?
Discussion: OWLMaker fails to build
Discussion: e7350279af
Discussion: Help on incompatible changes in 7 series
Discussion: Help on incompatible changes in 7 series
Discussion: Using libcurl in a BC++ 5.2 Old-OWL project
Discussion: Porting my codes to OWLNext 6.42
News: 2019/08/owlnext-6447-and-6362-updates
Wiki: 64-bit_OWLNext
Wiki: Contributing
Wiki: Convert_Borland_C++_resource_files_to_Visual_C++
Wiki: Dialog_Data_Transfer
Wiki: Exceptions_and_OWLNext
Wiki: Frequently_Asked_Questions
Wiki: Installing_OWLNext
Wiki: Knowledge_Base
Wiki: Links
Wiki: Main_Page
Wiki: Making_an_application_Unicode-ready
Wiki: Migrating_from_BC_to_VC
Wiki: OWLNext_Stable_Releases
Wiki: OWLNext_and_Data_Execution_Prevention
Wiki: OWLNext_modules_description
Wiki: OWL_Compatibility_modes
Wiki: OWL_Static_Library_Sectioning
Wiki: Replacing_the_Borland_C++_Class_Libraries
Wiki: Replacing_usage_of_BWCC
Wiki: Safe_Transfer_Buffers
Wiki: Strings_in_OWLNext
Wiki: Supported_Compilers
Wiki: Tools
Wiki: Upgrading_from_OWL_1.0
Wiki: Using_the_Microsoft_Layer_for_Unicode_with_OWLNext
Wiki: Windows_Message_Dispatch_in_OWLNext